T.J. Crowder (2017-02-25T22:40:00.000Z)
On Sat, Feb 25, 2017 at 7:22 PM, /#!/JoePea <joe at trusktr.io> wrote:
> I'm not sure what's the best way to phrase the subject (please advise on
the terminology)

Re terminology: I think you mean, will they all fire in the same job? (More
on jobs and job queues: https://tc39.github.io/ecma262/#sec-jobs-and-job-
queues)

> ...but for example, if we have a promise chain

First, before we get to the question of "turns," just a note on that code:
Remember that the result of `then` is always a promise. So writing:

```js
.then(() => Promise.resolve(someValue))
```

is adding an extra promise with no benefit; just use:

```js
.then(() => value)
```

and you'll still get a promise resolved with `value`. So no need for those
`Promise.resolve` calls (unless I'm missing a subtlety, which has been
known to happen).

> ```js
> const p = new Promise(r => setTimeout(r, 100))
>
> p
> .then(() => Promise.resolve(console.log('A')))
> .then(() => Promise.resolve(console.log('B')))
> .then(() => Promise.resolve(console.log('C')))
> ```
>
> , will the `console.log`s fire in the same turn when promise `p` settles,
or will they fire in three separate turns?

No, they're all queued as separate jobs -- but they're jobs that jump the
queue a bit (more on that in a minute). We can see this in [FulfillPromise](
https://tc39.github.io/ecma262/#sec-fulfillpromise) which calls
[TriggerPromiseReactions](https://tc39.github.io/ecma262/#
sec-triggerpromisereactions) which uses [EnqueueJob](https://tc39.
github.io/ecma262/#sec-enqueuejob) to add *each* reaction, as a separate
job, to the `"PromiseJobs"` queue.

Note that not all job queues are equal. In browsers, for instance, there
are *macrotasks* (or just *tasks*) and *microtasks* (where the JavaScript
spec uses the term "job," the HTML5 spec uses the term "task"). Macrotasks
are the big things you think of in browsers: DOM event handlers,
`setTimeout` callbacks, that kind of thing. Microtasks are things like
promise resolutions: The microtasks scheduled by a macrotask run just after
the macrotask completes, before the next macrotask runs (even if the next
macrotask was added to the macrotask queue before the microtasks were added
to the microtask queue).

E.g., microtasks like promise completions get priority over macrotasks like
`setTimeout` and DOM event handlers. That's part of why the spec
differentiates between the `"PromiseJobs"` queue and the `"ScriptJobs"`
queue (https://tc39.github.io/ecma262/#table-26).

Here's an example (https://jsfiddle.net/s44h3wtv/):

```js
new Promise(resolve => {
    setTimeout(resolve, 0);
    setTimeout(() => console.log("Next"), 0);
})
.then(() => console.log("A"))
.then(() => console.log("B"))
.then(() => console.log("C"));
```

We're resolving in a macrotask, and the *very next* scheduled macrotask is
to log "Next". And yet, the result of the above is:

```txt
A
B
C
Next
```

Note how the promise resolutions (microtasks) queued by the macrotask that
resolved the promise (the first `setTimeout`) were performed before the
next macrotask (the `setTimeout` logging "Next").

-- T.J.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170225/5853db86/attachment-0001.html>
tj.crowder at farsightsoftware.com (2017-02-25T22:45:58.563Z)
On Sat, Feb 25, 2017 at 7:22 PM, /#!/JoePea <joe at trusktr.io> wrote:
> I'm not sure what's the best way to phrase the subject (please advise on
> the terminology)

Re terminology: I think you mean, will they all fire in the same job? (More
on jobs and job queues: https://tc39.github.io/ecma262/#sec-jobs-and-job-
queues)

> ...but for example, if we have a promise chain

First, before we get to the question of "turns," just a note on that code:
Remember that the result of `then` is always a promise. So writing:

```js
.then(() => Promise.resolve(someValue))
```

is adding an extra promise with no benefit; just use:

```js
.then(() => value)
```

and you'll still get a promise resolved with `value`. So no need for those
`Promise.resolve` calls (unless I'm missing a subtlety, which has been
known to happen).

> ```js
> const p = new Promise(r => setTimeout(r, 100))
>
> p
> .then(() => Promise.resolve(console.log('A')))
> .then(() => Promise.resolve(console.log('B')))
> .then(() => Promise.resolve(console.log('C')))
> ```
>
> , will the `console.log`s fire in the same turn when promise `p` settles,
> or will they fire in three separate turns?

No, they're all queued as separate jobs -- but they're jobs that jump the
queue a bit (more on that in a minute). We can see this in [FulfillPromise](
https://tc39.github.io/ecma262/#sec-fulfillpromise) which calls
[TriggerPromiseReactions](https://tc39.github.io/ecma262/#sec-triggerpromisereactions) which uses [EnqueueJob](https://tc39.github.io/ecma262/#sec-enqueuejob) to add *each* reaction, as a separate
job, to the `"PromiseJobs"` queue.

Note that not all job queues are equal. In browsers, for instance, there
are *macrotasks* (or just *tasks*) and *microtasks* (where the JavaScript
spec uses the term "job," the HTML5 spec uses the term "task"). Macrotasks
are the big things you think of in browsers: DOM event handlers,
`setTimeout` callbacks, that kind of thing. Microtasks are things like
promise resolutions: The microtasks scheduled by a macrotask run just after
the macrotask completes, before the next macrotask runs (even if the next
macrotask was added to the macrotask queue before the microtasks were added
to the microtask queue).

E.g., microtasks like promise completions get priority over macrotasks like
`setTimeout` and DOM event handlers. That's part of why the spec
differentiates between the `"PromiseJobs"` queue and the `"ScriptJobs"`
queue (https://tc39.github.io/ecma262/#table-26).

Here's an example (https://jsfiddle.net/s44h3wtv/):

```js
new Promise(resolve => {
    setTimeout(resolve, 0);
    setTimeout(() => console.log("Next"), 0);
})
.then(() => console.log("A"))
.then(() => console.log("B"))
.then(() => console.log("C"));
```

We're resolving in a macrotask, and the *very next* scheduled macrotask is
to log "Next". And yet, the result of the above is:

```txt
A
B
C
Next
```

Note how the promise resolutions (microtasks) queued by the macrotask that
resolved the promise (the first `setTimeout`) were performed before the
next macrotask (the `setTimeout` logging "Next").

-- T.J.