Walkthrough of the following script (v8:6573).
var logFoo;
var promise1 = Promise.resolve().then( () => logFoo = () => console.log( "foo" ) );
promise1.then( () => logFoo() ).then( logFoo );
var logFoo;
state | value |
---|---|
logFoo |
undefined |
promise1 |
undefined |
enqueued microtasks | 0 |
logFoo
is declared, with an initial value undefined
.
var promise1 = Promise.resolve()
state | value |
---|---|
logFoo |
undefined |
promise1 |
undefined |
enqueued microtasks | 0 |
promise1
is declared. The initialization has not finished at this point, so its value
is still undefined
.
We reach https://tc39.github.io/ecma262/#sec-promise-resolve-functions step 11.a, which enqueues a microtask for all fulfilled handlers in the promise returned from Promise.resolve() --- but there are none, so no task has been enqueued yet.
(intermediateValue).then( () => logFoo = () => console.log( "foo" ) );
state | value |
---|---|
logFoo |
undefined |
promise1 |
Promise ({ [[PromiseState]]: "pending", [[PromiseResult]]: undefined, [[PromiseFulfillReactions]]: undefined, [[PromiseRejectReactions]]: undefined }) |
enqueued microtasks | 1 |
We reach https://tc39.github.io/ecma262/#sec-performpromisethen step 8.b. and enqueue a promise reaction job with the fulfilled handler. This is job #1.
promise1.then( () => logFoo() )
state | value |
---|---|
logFoo |
undefined |
promise1 |
Promise ({ [[PromiseState]]: "pending", [[PromiseResult]]: undefined, [[PromiseFulfillReactions]]: [ () => logFoo() ], [[PromiseRejectReactions]]: undefined }) |
enqueued microtasks | 1 |
As promise1 is still pending, no further tasks are queued up, but a fullfill handler is added to the Promise.
(intermediateValue).then( logFoo )
state | value |
---|---|
logFoo |
undefined |
promise1 |
Promise ({ [[PromiseState]]: "pending", [[PromiseResult]]: undefined, [[PromiseFulfillReactions]]: [ () => logFoo() ], [[PromiseRejectReactions]]: undefined }) |
enqueued microtasks | 1 |
Adds a fullfill handler (logFoo
, which is undefined
as job #1 has not yet had the opportunity to run)
to the Promise returned from step 4.
No job is enqueued yet as, it will not be queued until job #2 runs (per https://tc39.github.io/ecma262/#sec-promisereactionjob step 8.a.)
at this point, the script is complete, and the JS vm has the opportunity to run microtasks, or allow the browser to do more work such as run event handlers.
(() => logFoo = () => console.log( "foo" ))(undefined);
state | value |
---|---|
logFoo |
() => console.log( "foo" ) |
promise1 |
Promise ({ [[PromiseState]]: "fulfilled", [[PromiseResult]]: () => console.log( "foo" ) , [[PromiseFulfillReactions]]: undefined, [[PromiseRejectReactions]]: undefined }) |
enqueued microtasks | 1 |
logFoo is now a function which invokes console.log("foo");
.
The returned promise from Promise.resolve().then( () => logFoo = () => console.log( "foo" ) )
is fulfilled with the returned handler value, which is () => console.log( "foo" )
, and another
job is enqueued (job #2).
(() => console.log( "foo" ))( () => console.log( "foo" ) );
state | value |
---|---|
logFoo |
() => console.log( "foo" ) |
promise1 |
Promise ({ [[PromiseState]]: "fulfilled", [[PromiseResult]]: () => console.log( "foo" ) , [[PromiseFulfillReactions]]: undefined, [[PromiseRejectReactions]]: undefined }) |
enqueued microtasks | 1 |
"foo"
is logged to the terminal via console.log.
The returned Promise from the .then() call is fulfilled with the result of the handler, which is undefined
. Another
job is enqueued (job #3).
(defaultFulfillHandler)(undefined);
state | value |
---|---|
logFoo |
() => console.log( "foo" ) |
promise1 |
Promise ({ [[PromiseState]]: "fulfilled", [[PromiseResult]]: () => console.log( "foo" ) , [[PromiseFulfillReactions]]: undefined, [[PromiseRejectReactions]]: undefined }) |
enqueued microtasks | 0 |
the value originally passed to Promise.prototype.then
was undefined, so this just
calls a default handler, propagating the undefined value to the next promise in
the chain. That promise has no fulfill reactions, so no further promise jobs are enqueued.