Promise release varies between NodeJ and browser

The next block of code is executed differently between Node and the browser. There are, of course, different modes, different processing times and race options. But in my understanding of Promises, this code needs to be consistent across environments.

I am expecting Chrome / browser output. I am not expecting the result of NodeJs. I don't understand why each chain is newPromise

then

not complete before the chain masterPromise

then

continues. In other words, since the new promise returns to the promise chain masterPromise

at that time fn

, I expect the new Promise chain to complete before the masterPromise chain of promises resumes.

I would really like if someone could punch a hole in the following implementation and explain why the NodeJs result is valid!

Using chrome 44 and Node 12.6.

Example:

'use strict';
var masterPromise = Promise.resolve();
var numbers = [ 1, 2, 3 ];

// function returns a new promise that fulfills in 100ms
// it logs two bits of information--one pre-resolve, & one post-resolve.
// because a `.then` is registered immediately, before the promised is
// fulfilled, i would expect the post-resolve console.log to be logged before
// any other logging
var returnNewPromise = function(number) {
    var resolve;
    var newPromise = new Promise(function(r) { resolve = r; });
    newPromise.then(function() { console.log('registered ' + number + ' (verbatim, syncronous echo)'); });
    setTimeout(function() {
        console.log('registered ' + number);
        resolve();
    }, 100);
    return newPromise;
};

numbers.forEach(function(number) {
    var getChildPromise = function(number) {
        return returnNewPromise(number);
    };
    return masterPromise.then(function() {
        return getChildPromise(number);
    });
});

      

Node:

registered 1
registered 2
registered 3
registered 1 (verbatim, syncronous echo)
registered 2 (verbatim, syncronous echo)
registered 3 (verbatim, syncronous echo)

      

Chrome:

registered 1
registered 1 (verbatim, syncronous echo)
registered 2
registered 2 (verbatim, syncronous echo)
registered 3
registered 3 (verbatim, syncronous echo)

      

+3


source to share


2 answers


I don't understand why every chain is newPromise

then

not complete before the chain masterPromise

then

continues. The new Promise returns to the Promise Chain masterPromise

at that time fn

, so shouldn't you wait for that before masterPromise renews promises?

Not. It seems that your misunderstanding is related to the fact that "masterPromise chain": such does not exist.
You have one masterPromise

and then you have three different calls connected to it then

. When masterPromise

resolved (which immediately) it sees 3 callbacks and calls them all in the order they were registered. They don't care what these callbacks do, whether they are asynchronous or not, and don't wait for the results of their promises. In your case, they all create promises and push their subchains through them, but these 3 subchains are completely independent of each other.

Perhaps your more verbose logging code will help you understand what you are doing:

function delay(number) {
    console.log("creating promise for", number);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('resolving promise with', number);
            resolve(number);
        }, 100);
    });
};
function result(n) {
    console.log("received", number);
}

var masterPromise = Promise.resolve();

masterPromise.then(function(){ delay(1).then(result); }); // chain 1
masterPromise.then(function(){ delay(2).then(result); }); // chain 2
masterPromise.then(function(){ delay(3).then(result); }); // chain 3
console.log("created chains");

      



The log you see here

// .then chain 1    -------,
// .then chain 2    ------- \ -,
// .then chain 3    -------- \ -\ -,
created chains                |  |  |
                              |  |  | 3 then callbacks in the order they were registered
creating promise for 1      <´   |  |
// setTimeout 100   -----,       |  |
                          \     /   |
creating promise for 2     | <-´    |
// setTimeout 100   ------ |-,      /
                           |  \    /
creating promise for 3     |  | <-´
// setTimeout 100   ------ |- |-,
                           |  |  \
…                          |  |  | 3 timeout callbacks in the order they were scheduled
                           |  |  |
resolving promise with 1 <´   |  |
// resolve()                  |  |
[]                           /  |
resolving promise with 2  <-´    |
// resolve()                     /
[]                             /
resolving promise with 3   <---´
// resolve()
[]

      

Here we see three (independent) calls resolve()

. They will schedule their callback ( result

) as soon as possible . And here's the difference between node and Chrome: the former executes the same timeout callbacks (they were scheduled at the same time with the same timeout) on the same tick, while Chrome uses separate ticks. So in node "asap" after three callbacks, while in Chrome it sits in between. Both implementations are fine.

+2


source


I don't understand why each newPromise chain is not immediately executed upon its resolution.

then-the callbacks are not called immediately.

var resolve;
new Promise(function (r) { resolve = r; })
    .then(function () { console.log(2); });
resolve();
console.log(1);

      

Magazine:

1
2

      

Promise resolution behaves like setTimeout

zero latency.



update:

Comparison with is setTimeout

not entirely correct due to limitations: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout#Minimummaximum_delay_and_timeout_nesting Asynchronous similarity promises.

Update2:

-----------+------------
wait       |  resolved
-----------+------------
timeout1   |             initial state
timeout2   |
-----------+------------
           | timeout1    after 100 ms
timeout2   |
-----------+------------
           | resolve1    then Chrome variant
           | timeout2
-----------+------------
           | timeout2    or Node variant
           | resolve1
-----------+------------

      

Both options meet the specification. It seems that chrome queues allow callbacks before subsequent timeout callbacks.

+2


source







All Articles