Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Here are some simple questions based on behaviour I noticed in the following example running in node:

Q('THING 1').then(console.log.bind(console));
console.log('THING 2');

The output for this is:

> "THING 2"
> "THING 1"

Questions:

1) Why is Q implemented to wait before running the callback on a value that is immediately known? Why isn't Q smart enough to allow the first line to synchronously issue its output before the 2nd line runs?

2) What is the time lapse between "THING 2" and "THING 1" being output? Is it a single process tick?

3) Could there be performance concerns with values that are deeply wrapped in promises? For example, does Q(Q(Q("THING 1"))) asynchronously wait 3 times as long to complete, even though it can be efficiently synchronously resolved?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
336 views
Welcome To Ask or Share your Answers For Others

1 Answer

This is actually done on purpose. It is to make it consistent whether or not the value is known or not. That way there is only one order of evaluation and you can depend on the fact that no matter if the promise has already settled or not, that order will be the same.

Also, doing it otherwise would make it possible to write a code to test if the promise has settled or not and by design it should not be known and acted upon.

This is pretty much the as doing callback-style code like this:

function fun(args, callback) {

    if (!args) {
        process.nextTick(callback, 'error');
    }
    // ...
}

so that anyone who calls it with:

fun(x, function (err) {
  // A
});
// B

can be sure that A will never run before B.

The spec

See the Promises/A+ Specification, The then Method section, point 4:

onFulfilled or onRejected must not be called until the execution context stack contains only platform code.

See also the the note 1:

Here "platform code" means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a "macro-task" mechanism such as setTimeout or setImmediate, or with a "micro-task" mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or "trampoline" in which the handlers are called.

So this is actually mandated by the spec.

It was discussed extensively to make sure that this requirement is clear - see:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...