domenic / promises-unwrapping

The ES6 promises spec, as per September 2013 TC39 meeting
1.24k stars 95 forks source link

Formalize "queue a microtask" #64

Closed domenic closed 10 years ago

domenic commented 10 years ago

Will want to harmonize with @dherman and @jorendorff's work on the module loader spec and whatever hook they're using there.

My current approach is that sometimes I say "queue a microtask to do the following" and then start a new indentation level of numbered list. Everything inside there is assumed to take place in a new microtask.

Note that steps inside there can throw exceptions, which I expect to crash that sequence of steps but not the surrounding function.

jorendorff commented 10 years ago

On Mon, Oct 28, 2013 at 12:50 AM, Domenic Denicola <notifications@github.com

wrote:

Will want to harmonize with @dherman https://github.com/dherman and @jorendorff https://github.com/jorendorff's work on the module loader spec and whatever hook they're using there.

My current approach is that sometimes I say "queue a microtask to do the following" and then start a new indentation level of numbered list. Everything inside there is assumed to take place in a new microtask.

Note that steps inside there can throw exceptions, which I expect to crash that sequence of steps but not the surrounding function.

Timely mail! We are furiously specing the loader. TBH promises are further along and we were not going to come to this pass for a few days yet.

I think @dherman wanted to avoid nested lists, in favor of language like "Queue a microtask to call Whatever(arg1, arg2)." and then you write a separate abstract operation below. We hadn't talked about it much yet. I'll ask today. To me it sounds like a mix is best; in some cases a short nested list will be more readable...

You know—the loader spec actually almost doesn't need this anymore since we switched the API to promises. I'm just using promises for everything. So, thanks! The only place I have to explicitly queue tasks is when I expect a user hook to return a Promise and it may return some badly-behaved thenable object instead. Dealing with all the crazy things a user-provided object could do is a huge pain. :-P

-j

domenic commented 10 years ago

The only place I have to explicitly queue tasks is when I expect a user hook to return a Promise and it may return some badly-behaved thenable object instead. Dealing with all the crazy things a user-provided object could do is a huge pain. :-P

Haha, yes, I so agree! But, I can perhaps spare you this pain: you could just cast the returned object to a promise instead, using my spec hooks!

What behavior would be most helpful?

jorendorff commented 10 years ago

The former.

This is a bit of a miracle in terms of the effect it will have on our code. Thanks, Domenic.

domenic commented 10 years ago

Excellent, that's just what I'm currently calling Promise.cast. I'll extract that out into a ToPromise abstract operation you can use.

allenwb commented 10 years ago

I agree, no nested algorithms. Where those occur today(in RegExp) they're really hard to understand.

I suggest going one step further than Jason's suggestion.

Actually define an abstraction called a "Microstak". eg

1.2.3 Microtask Whenever(arg1, arg2) steps...

We will then have an abstraction operation QueueMicrotask(task, argumentList)

and you an call it as:

  1. Perform QueueMicrotask(Whenever, (1,2)).
domenic commented 10 years ago

@jorendorff Extracted CastToPromise(C, x). You will probably be doing CastToPromise(%Promise%, x).

jorendorff commented 10 years ago

Hmm. Does this operation try to handle user-implemented thenables at all? I think we want to support them, but with some care.

domenic commented 10 years ago

It does; they are wrapped in a real promise, and calling .then on the resulting real promise will trigger the thenable's then, but enforce all promise-related guarantees (e.g. handlers will be called asynchronously).

jorendorff commented 10 years ago

Where is that implemented? Sorry, I'm looking at README.md and I see the CastToPromise operation, but I don't see where it checks IsThenable(x) or how it produces the true-Promise wrapper.

domenic commented 10 years ago

If IsPromise(x) is false (which will be the case for thenables), it creates a new promise from the C parameter and resolves it to x.

jorendorff commented 10 years ago

Oh, OK. So this is just the same behavior as what happens when a function that's an argument to Promise.prototype.then returns. Great. Thanks.

domenic commented 10 years ago

@allenwb I followed your strategy. It turns out only a single microtask was necessary. Let me know what you think. The spec delta for the QueueMicrotask function is also kind of sketchy, so revisions welcomed there.