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

Give guidance on how to migrate void-returning callback APIs to promise-returning #24

Open
domenic opened this issue Apr 2, 2014 · 11 comments
Assignees

Comments

@domenic
Copy link
Member

domenic commented Apr 2, 2014

This will help spec authors looking to modernize.

@annevk
Copy link
Member

annevk commented Sep 5, 2014

I was looking at "Queue Tasks to Invoke User Code" and I don't understand why the event is not dispatched from a specification-.then() registered callback. That seems like a better way to synchronize those tasks.

@annevk
Copy link
Member

annevk commented Sep 5, 2014

That's also how I would expect this to work. To just pass the callback to .then() on the promise you're about to return from the API.

@domenic
Copy link
Member Author

domenic commented Sep 5, 2014

(Not sure that's related to this issue, but I'll run with it.)

The given steps seem to me to correspond to

return new Promise(resolve => {
  setTimeout(() => {
    resolve();
    window.dispatchEvent("timerfinished", ...);
  }, ms);
});

You seem to be suggesting

var p = new Promise(resolve => {
  setTimeout(resolve, ms);
});

p.then(() => window.dispatchEvent("timerfinished", ...));

return p;

These certainly do different things, but I am not sure why one is better than the other.

@annevk
Copy link
Member

annevk commented Sep 7, 2014

No, what the guide is suggesting is

return new Promise(resolve => {
  setTimeout(() => {
    resolve();
    setTimeout(() => { window.dispatchEvent("timerfinished", ...) }, 0);
  }, ms);
});

with the outer setTimeout being some kind of end-of-asynchronous-behavior-but-not-yet-synchronized-with-main-thread and the inner setTimeout being a next task thingy.

@domenic
Copy link
Member Author

domenic commented Sep 7, 2014

Now I'm confused. I was pretty sure "queue a task" was just a mechanism of getting back to the main event loop from outside of it.

In this sense, in my translation, both resolve() and window.dispatchEvent("timerfinished", ...) are technically from outside the event loop. If we were to rewrite this to be explicit, we'd say:

return new Promise(resolve => {
  delayOnAnotherThread(() => {
    getBackToMainEventLoopViaPromiseMicrotaskQueue(() => resolve());
    getBackToMainEventLoopViaTaskQueue(() => window.dispatchEvent("timerfinished", ...));
  }, ms);
});

Does this seem right?

If so, I still don't see why this is worse than

var p = new Promise(resolve => {
  delayOnAnotherThread(() => {
    getBackToMainEventLoopViaPromiseMicrotaskQueue(() => resolve());
  }, ms);
});

p.then(() => window.dispatchEvent("timerfinished", ...));

return p;

I guess in the latter you don't have to queue a task?

@annevk
Copy link
Member

annevk commented Sep 8, 2014

Yes. In the latter case the other thing is that the event is dispatched at the same time the promise callbacks are invoked rather than later.

It seems better to have these callbacks invoked at roughly the same point rather than at different points with an arbitrary amount of UI and network tasks between. Might be just me though.

@domenic
Copy link
Member Author

domenic commented Feb 10, 2015

Discussions with @ddorwin have made it clear this guide is massively failing to give good guidance on the type of things talked about in this thread. (See e.g. w3c/encrypted-media#19.) I think we should prioritize giving clear patterns for:

  1. Doing something after a promise callback triggers
  2. Doing something before a promise callback triggers

I'll try and prioritize that.

@plinss plinss added this to the 2020-06-01-week milestone May 4, 2020
@kenchris
Copy link

kenchris commented May 5, 2020

There is an newer comment from 24 February 2016: w3c/encrypted-media#19 (comment)

As I read this, the suggestion is that event handlers should run after promise fulfillment handlers (if additional microtasks (ie fulfilled promises) are run, they all run to completion before cycling the event loop.)

I also understand that this means calling in following in this order:

  • resolve a promise (this automatically queues a task to resolve promise)
  • queues a task to fire the event.

@annevk
Copy link
Member

annevk commented May 5, 2020

No, you want a single task to do both. I suspect that what happens these days is that the event is dispatched and promise resolving can be observed afterwards. So the event happens at an earlier point. I don't think anything went for my more complicated setup where the event would be dispatched as part of a "promise callback".

@kenchris
Copy link

kenchris commented May 5, 2020

Discussed with @littledan. I guess that is the advice we need to give is:

  • if not on main thread (runs in parallel), you must query a task for either dispatching an event or fulfilling a promise
  • you should use the same task for both cases
  • end result is that the promise fulfillment will run later than the event

@annevk
Copy link
Member

annevk commented May 5, 2020

Yeah. Also, there's no such thing is automatically queuing of tasks anymore. Someone could build such an abstraction again (and add it to HTML), but it would have to take more parameters and it's not clear we have that many consumers with such basic tasks that it's worth doing.

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

No branches or pull requests

5 participants