Promise.resolve
指定返回已解决的承诺(令人兴奋,对吧?25.4.4.5、25.4.1.5、25.4.1.3。)。a.then()
因此立即将作业加入队列(25.4.5.3.1 https://tc39.github.io/ecma262/#sec-performpromisethen,每次都执行步骤 8)。.then()
根据此规范,永远不会返回已履行的承诺(对于一些有趣的事情,请尝试Promise.resolve().then()
在您的 Chrome 控制台中¶
让我们为承诺命名a.then(v => Promise.resolve("A"))
及其一些相关的规格状态p1². This .then()
排队要调用的作业(25.4.2.1 https://tc39.github.io/ecma262/#sec-promisereactionjob) a.then(v => Promise.resolve("A"))
如上所述。
首先.then(v => console.log(v))
附加对应于的承诺反应v => console.log(v)
₁ 待处理承诺的履行反应列表p1 (still 25.4.5.3.1 https://tc39.github.io/ecma262/#sec-performpromisethen).
承诺a.then(v => "B")
can be p2。目前它的工作方式相同。
我们已经到了脚本的结尾。
第一份工作时,对应v => Promise.resolve("A")
,出列并调用(再次25.4.2.1 https://tc39.github.io/ecma262/#sec-promisereactionjob), a then
在结果中发现(这是重要的部分),导致另一个作业排队(25.4.1.3.2 https://tc39.github.io/ecma262/#sec-promise-resolve-functions,步骤 12),无论该结果的承诺状态如何。
下一个作业将出列并被调用。一个可调用的then
is not根据结果发现,所以p2立即满足(25.4.1.3.2 https://tc39.github.io/ecma262/#sec-promise-resolve-functions再次执行步骤 11a) 并为每个任务排队p2的满足反应。
我将在这里停止这一级别的解释,因为Promise.resolve("A").then
开始整个then
再次序列。不过,您可以看到这是怎么回事:作业队列是一个queue,并且将产生输出的一个函数已在队列中,而另一个尚未添加。队列中的那个将首先运行。
正确的输出是 B 后跟 A。
那么,既然这样,为什么 Chrome 中的答案在一个页面中是错误的呢?这不是一些 Stack Overflow 片段填充程序;您可以使用一些 HTML 本身或在 Node.js 中重现它。我的猜测是,这是一个违反规范的优化。
'use strict';
class Foo extends Promise {}
let a = Promise.resolve();
a.then(v => Foo.resolve("A")).then(v => console.log(v));
a.then(v => "B").then(v => console.log(v));
的替代定义thenable
带着这个乐趣node --allow_natives_syntax
script!
'use strict';
const thenable = p => ({ then: p.then.bind(p) });
//const thenable = p => p;
let a = Promise.resolve();
a.then(v => {
%EnqueueMicrotask(() => {
%EnqueueMicrotask(() => {
console.log("A should not have been logged yet");
});
});
return thenable(Promise.resolve("A"));
}).then(v => console.log(v));
a.then(v => "B").then(v => console.log(v));
¹ For posterity: it’s a resolved promise in Chrome 61.0.3163.100.
² That’s less specific than the spec, but this is an answer trying to describe the spec and not a spec. With any luck, it’s even right, too.