Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deferred: invoke processes in async groups instead of individually #3228

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

jbedard
Copy link
Contributor

@jbedard jbedard commented Jul 13, 2016

This is a first shot at #3227.

This does not invoke deferredTick anywhere else yet.

@mention-bot
Copy link

@jbedard, thanks for your PR! By analyzing the annotation information on this pull request, we identified @gibson042, @mgol and @jaubourg to be potential reviewers

// Support: Promises/A+ section 2.3.3.3.1
// https://promisesaplus.com/#point-57
// Re-resolve promises immediately to dodge false rejection from
// subsequent errors
if ( depth ) {
process();
deferredTick();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this specific line could actually change the execution order of processs.

Previously this single process would be invoked before other scheduled async ones. Now it will invoke other scheduled ones first, then this one last, but it is still "immediately" (see comment a couple line above).

Can anyone think of a case where this is wrong?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the only possible callback that might throw and not be caught is the last one, right?

However, would something like deferred.then(fn1).done(fn2) force fn1 to be synchronous in order to run fn2? If the queue were per-Deferred that wouldn't happen, but it is global/shared.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the only possible callback that might throw and not be caught is the last one, right?

I'm not sure actually. Can you think of any examples where a throwing function would be pushed onto processQueue?

However, would something like deferred.then(fn1).done(fn2) force fn1 to be synchronous in order to run fn2?

All the scenarios I've tried seem to be valid to. Some examples... (where fn1 always executes before fn2, fn3 before fn4 etc).

deferred.then(fn1).done(fn2)
var def = $.Deferred();
def.then(fn1).done(fn2);
def.resolve(-1);
$.when(5).then(fn3);
var def = $.Deferred();
def.then(fn2).done(fn3);
$.when(5).then(fn1);
def.resolve(-1);
var def = $.Deferred();
def.then(fn2).done(fn3);
def.resolve(-1);
$.when(5).done(fn1);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think the case I was looking for was deferred.then(fn1).notify(fn2) since I think that's the only time special comes into play? This definitely could use a @gibson042 look.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notify case is an issue, see 4bc074b

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR does introduce some sequence jumping. Note how callbacks follow an orderly progression with the current codebase, but the .thens get clustered and pulled forward by this PR. That's not a problem (and is in fact the whole point), but the other part is potentially a problem: that the mere introduction of a bound Deferred (i.e., constructed by a .then that returned a thenable) affects all Deferred callbacks, pulling forward to pseudo-synchronicity callbacks that previously waited for the next event loop in front of other callbacks.

I'm against this PR as-is, but in favor of the broader refactoring that was hoped for when the Deferred changes first landed, to abstract out Promises/A+ compatibility code for both Deferred#then and jQuery.when, and in particular to eliminate this synchronous call (which exists to catch bad then implementations that throw after invoking a callback) by incrementing maxDepth earlier in the resolution process.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to revert this one line?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because then things would probably fall out of spec. I'm instead advocating for broader changes that would eliminate the need for doing something different when depth > 0, at which point there won't be any queue jumping.

@timmywil timmywil added this to the Future milestone Jul 13, 2016
function() {
try {
mightThrow();
} catch ( e ) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swallowing errors from progress callbacks is a problem. We just went through a big exercise with ready to prevent its analogous situation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was mainly just to test this out. I'm thinking that exceptions from a progress callback should be handled the same as exceptions in a success/error callback (~20 lines down). If we're ok with that then I think these two methods wrapping mightThrow can be combined and the special check will go within that single wrapper. Basically special just means that mightThrow throwing does not reject the promise...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So send them through exceptionHook? Yeah, that makes sense.

Base automatically changed from master to main February 1, 2021 22:02
@mgol
Copy link
Member

mgol commented Sep 17, 2021

Closing & re-opening the PR to trigger the EasyCLA check...

@mgol mgol closed this Sep 17, 2021
@mgol mgol reopened this Sep 17, 2021
@linux-foundation-easycla
Copy link

CLA Not Signed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants