Skip to content

Instantly share code, notes, and snippets.

@caitp
Created July 6, 2017 12:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save caitp/bbd844f0528bf0d3dd123ddd591f910a to your computer and use it in GitHub Desktop.
Save caitp/bbd844f0528bf0d3dd123ddd591f910a to your computer and use it in GitHub Desktop.

Walkthrough of the following script (v8:6573).

var logFoo;
var promise1 = Promise.resolve().then( () => logFoo = () => console.log( "foo" ) );
promise1.then( () => logFoo() ).then( logFoo );

1. var logFoo;

var logFoo;
state value
logFoo undefined
promise1 undefined
enqueued microtasks 0

logFoo is declared, with an initial value undefined.

2. var promise1 = Promise.resolve()

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.

3. .then( () => logFoo = () => console.log( "foo" ) );

(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.

4. promise1.then( () => logFoo() )

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.

5. .then( logFoo )

(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.

6. job #1

(() => 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).

6. 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).

6. 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.

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