以下是一些基于我在以下示例中注意到的行为的简单问题:在节点中运行:
Q('THING 1').then(console.log.bind(console));
console.log('THING 2');
这个输出是:
> "THING 2"
> "THING 1"
1)为什么Q
实现了在对一个立即知道的值运行回调之前等待?为什么没有Q
足够智能以允许第一行在第二行运行之前同步发出其输出?
2)输出"THING 2"
和"THING 1"
之间的时间间隔是多少?这是一个单一的流程吗?
3)对于承诺中深深包含的价值观,是否存在业绩问题?例如,Q(Q(Q("THING 1")))
是否异步等待3次完成,即使它可以有效地同步解析?
答案 0 :(得分:1)
这实际上是故意的。无论值是否已知,都要使其保持一致。这样只有一个评估顺序,你可以依赖这样一个事实,即无论承诺是否已经解决,该顺序将是相同的。
另外,这样做可以编写代码来测试承诺是否已经解决,并且在设计时不应该知道并采取行动。
这就像做回调式代码一样:
function fun(args, callback) {
if (!args) {
process.nextTick(callback, 'error');
}
// ...
}
以便任何使用以下方式调用它的人:
fun(x, function (err) {
// A
});
// B
可以确定A在B之前永远不会运行。
请参阅Promises/A+ Specification,The then
Method部分,第4点:
在执行上下文堆栈仅包含平台代码之前,不得调用
onFulfilled
或onRejected
。
另请参阅the note 1:
此处"平台代码"表示引擎,环境和承诺实现代码。实际上,这个要求确保onFulfilled和onRejected异步执行,然后调用事件循环,然后调用新堆栈。这可以通过"宏任务"来实现。机制,如setTimeout或setImmediate,或与"微任务" MutationObserver或process.nextTick等机制。由于promise实现被认为是平台代码,它本身可能包含任务调度队列或" trampoline"在其中调用处理程序。
所以这实际上是规范要求。
为了确保这一要求是明确的,我们进行了广泛的讨论 - 见: