Search code examples
javascriptgithubjestjspromisepull-request

Is `Promise.resolve().then(f)` equivalent to `Promise.resolve(f())`?


In the codebase of async-pool, there is this statement:

const p = Promise.resolve(iteratorFn(item, iterable));

I believe that this statement is equivalent to:

const p = Promise.resolve().then(() => iteratorFn(item, iterable));

...as both statements resolve a promise and execute iteratorFn(item, iterable) asynchronously.

I would like to confirm if my assumption is correct and understand how I can validate it. I would then write appropriate unit tests to ensure the behavior of this code.


Solution

  • You wrote:

    both statements resolve a promise and execute iteratorFn(item, iterable) asynchronously.

    This is not true. The original code:

    const p = Promise.resolve(iteratorFn(item, iterable)); 
    

    ...executes iteratorFn synchronously. In other words, first iteratorFn is executed, then resolve, and then p is assigned the resolved promise.

    While here:

     const p = Promise.resolve().then(() => iteratorFn(item, iterable));
    

    resolve is called first, then then and then a pending(!) promise is assigned to p. Code will then continue with whatever next statement is to be executed synchronously. The callback that has been passed to then() will be called when the engine processes its microtask queue, so after the call stack is empty. Then iteratorFn will get executed, which will resolve the promise p.

    We can see the difference in behaviour in this snippet:

    function iteratorFn(arg) {
        console.log("running iteratorFn with argument " + arg);
    }
    
    console.log("executing original code");
    const p = Promise.resolve(iteratorFn("p")); 
    console.log("p has been assigned");
    
    console.log("executing customised code");
    const q = Promise.resolve().then(() => iteratorFn("q")); 
    console.log("q has been assigned");
    console.log("------------- end of synchronous code -----------------");