What determines the call order of deferred functio

2019-04-25 17:22发布

问题:

Deferring the execution of functions, for example in custom event handling, is a common pattern in JavaScript (see, for example here). It used to be that using setTimeout(myFunc,0) was the only way to do this, however with promises there is now an alternative: Promise.resolve().then(myFunc).

I had assumed that these would pretty much do the same thing, but while working on a library which included custom events I thought I'd find out if there was a difference, so I dropped the following block into node:

var logfn=function(v){return function(){console.log(v)}};

setTimeout(logfn(1),0);
Promise.resolve().then(logfn(2));
logfn(3)();

I was expecting to see on the console 3, 1, 2 but instead I saw 3, 2, 1. So in other words the Promise is NOT equivalent to using setTimeout and comes out of the blocks first. At least in Node.

I repeated the test in Chrome and Firefox with the same result, however in Edge it came out as 3, 1, 2. I would also expect non-native promise libraries to use setTimeout under the hood so would come out the same as Edge.

What determines the order of these calls being resolved? What model is used by these different environments to determine execution order? Does any of the above represent standard or non-standard behaviour?

PS I'm defniately not suggesting relying on any of this staying consistant, I'm just curious.


After the answer given below pointed me in the right direction, and as mentioned briefly in the comment below, I found the complete answer in an excellent article by Jake Archibald (with an example almost identical to my code above) which I though I'd add up here rather than leaving it buried in a comment.

回答1:

ll depends how resolve() was internally implemented - probably you observe difference between setTimeout(fn, 0) and Edge implementations for setImmediate(fn)

Please consider the article - http://www.mattgreer.org/articles/promises-in-wicked-detail/ and the way how resolve method was implemented.

function resolve(value) {
    // force callback to be called in the next
    // iteration of the event loop, giving
    // callback a chance to be set by then()
    setTimeout(function() {
        callback(value);
    }, 1);
}

Than some explenations can be found at priority between setTimeout and setImmediate

From Microsoft documentation - https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/performance/efficient-script-yielding/ and one more link - setImmediate method