Bug Tracker

Opened 6 years ago

Closed 5 years ago

#14510 closed bug (migrated)

Improve API interoperability with standard Promise

Reported by: jzaefferer Owned by:
Priority: high Milestone: 1.12/2.2
Component: deferred Version: 1.10.2
Keywords: Cc:
Blocked by: Blocking:

Description

Discussed this at the jQuery team meeting in Amsterdam: The spec is still changing a lot (within whatwg and draft pages on github), so we'll wait for it to ship, unprefixed, not behind a flag, in stable browsers first.

Once that happened, we should change/fix our implementation to match the spec (and shipped implementation).

Can use .pipe() to continue using any jQuery-specific functionality.

Change History (19)

comment:1 Changed 6 years ago by timmywil

Component: unfileddeferred
Priority: undecidedhigh
Status: newopen

comment:2 Changed 6 years ago by dj.gilcrease@…

Make jQuery.Defered / promise closer to conforming to the specification around exceptions. I have not checked the full compliance tests from https://github.com/promises-aplus/promises-tests but I have setup a test that shows the exception handling working as expected http://jsfiddle.net/yEXL4/1/

Pull Request @ https://github.com/jquery/jquery/pull/1462

comment:3 Changed 6 years ago by dmethvin

I don't think this is the right way to go. You're swallowing an exception silently and it will only be reported (poorly) if the user has the foresight to attach a fail handler. See #11193, #11292.

Even in the current proposed spec discussions there's some handwaving about needing browser support in dev tools to be able to debug properly.

What I'd prefer to do is have it so that users can opt into standard ES6 Promises or a compliant polyfill. Retroactively changing the semantics of Deferred in a significant way seems like a bad idea, especially with no built-in support to notify about unhandled promise rejections.

comment:4 Changed 6 years ago by markelog

This ticket requires clarification.

Specification that mentioned in ticket description is this one which refers to Domenic repository.

There is also promises/A and promises/A+ "proposals". Which are not much of a relevance right now. Plus upcoming draft of ES6 which should also have Promise clause.

DOM specification is in the draft stage, but it's already implemented in two browsers – Firefox (Nightly) and Chrome (Canary) without any prefixes, both browsers however has some implementation mistakes.

New specification defines new API which significantly differs from the jQuery Deferred, aside from methods like "cast", "catch", etc; it also has these behaivor differences:

  1. Guarantee asynchronous execution
  2. Swallows errors then passes and propagate them to the stack of rejection handlers
  3. Does not have progress handler in "then" signature
  4. Always passes only one argument to successful/failed callbacks

comment:5 Changed 6 years ago by dmethvin

It's definitely good to emphasize that Promises/A+ is just a proposal and not a standard to comply with. jQuery has had Deferred for several years now and I would guess it has the most number of users of any Promise/Deferred implementation that exists today. Let's not break that code, keep Deferred the way it is, and look for ways to let developers use the emerging standard.

There has been some lively discussion around the addition of a .done() method to ES6 Promises that would not swallow exceptions, but it doesn't seem to be slated for the first iteration of the standard. I think that's a shame, because .then() can be built from .done() but not the other way around. Without the proposed browser support for exposing unhandled exceptions, Promises are going to be very difficult to debug.

comment:6 in reply to:  4 Changed 6 years ago by Rick Waldron

Replying to markelog:

This ticket requires clarification.

Specification that mentioned in ticket description is this one which refers to Domenic repository.

This is the Promises specification that will be in ES6

comment:7 Changed 6 years ago by domenic@…

Promises/A+ is a standard and is the basis for the ES6 promises specification. All promises that follow the ES6 promise specification will pass all Promises/A+ tests. The ES6 promises spec is in effect a superset of the Promises/A+ spec.

comment:8 Changed 6 years ago by anonymous

.then() can be built from .done() but not the other way around.

This is false.

Promise.prototype.done = (onFulfilled, onRejected) {
  this.then(onFulfilled, onRejected).catch(e => setTimeout(() => throw e, 0));
};

comment:9 Changed 6 years ago by dmethvin

Re-throwing an error object that has propagated to you isn't the same as letting the browser handle the error at the point where it occurred. A lot of important error context is lost, especially on older browsers (which 1.x still supports).

However, that particular pull request listed above is about trying to turn Deferred into Promises/A+. We can't do that, it would break a few years worth of existing code that is already using Deferred. Nobody wants to break the web. Instead we expect to support ES6 Promises like I mentioned above. That seems like a good approach?

EDIT: Clarified the subject; the reason this ticket isn't closed is because we expect to support ES6 Promises but are not changing Deferred.

Last edited 6 years ago by dmethvin (previous) (diff)

comment:10 Changed 6 years ago by domenic@…

I guess it's unclear what the OP meant by

Make promises spec-compliant

... we should change/fix our implementation to match the spec (and shipped implementation).

Can use .pipe() to continue using any jQuery-specific functionality.

It sounds like you are saying something different from the OP, wherein you do not change/fix your implementation to match the spec, but instead somehow support real promises (unclear how).

comment:11 Changed 6 years ago by dmethvin

Reading through this, I agree it's unclear. The pull request referencing this issue was misplaced, since the OP doesn't mention changing our Deferred at all. If it becomes too confusing we can close this and open a new ticket with a more specific title.

comment:12 Changed 6 years ago by m_gol

I was at the Amsterdam meeting where it was discussed. OP says about compliance with ES6 spec. If wording is not clear, we can modify title & text of the issue but I'd prefer not to re-create one since discussion already started here.

comment:13 Changed 6 years ago by m_gol

We can discuss it in San Diego but, surprisingly, jaubourg seemed ok to switch once at least 2 stable browsers implement the new spec while keeping pipe with current semantics.

I'd like to see how much code would be affected, I don't think many people relied (in the production code) on the promise throwing errors as a way of flow control. OTH, for jQuery even a small amount can be a lot.

There's a larger question of how we deprecate old APIs, e.g. in case of $.ajax and the planned $.xhr. Will we ever be able to actually remove the former? The question here is of similar concern.

comment:14 Changed 6 years ago by calvin.metcalf@…

Chrome beta implements them and Firefox beta has them out from under a flag, so 2 stable browsers will be soon.

comment:15 in reply to:  14 Changed 6 years ago by markelog

Replying to calvin.metcalf@…:

Chrome beta implements them and Firefox beta has them out from under a flag, so 2 stable browsers will be soon.

See ticket description – "so we'll wait for it to ship, unprefixed, not behind a flag, in stable browsers first"

comment:16 Changed 6 years ago by anonymous

Unwrapping thenables is also a change you should consider doing. It's in the spec and it's useful.

comment:17 Changed 6 years ago by dmethvin

Summary: Make promises spec-compliantImprove API interoperability with standard Promise

I've edited the title to be more in line with what we actually plan to do for 1.12/2.2. We are not converting our internal uses of $.Deferred to the emerging Promise implementations, the semantics of the two differ too much and Promise lacks several features that $.Deferred uses, such as progress callbacks and multiple arguments.

However, we do plan on accepting Promise as an input where appropriate (e.g., $.when). and ensuring that $.Deferred works as a thenable.

comment:18 Changed 5 years ago by dmethvin

Milestone: None1.12/2.2

comment:19 Changed 5 years ago by m_gol

Resolution: migrated
Status: openclosed
Note: See TracTickets for help on using tickets.