ANi*_*sus 9 javascript ecmascript-6 es6-promise
为了理解ES6 promise的执行顺序,我注意到链接处理程序的执行顺序受前一个处理程序是返回值还是promise的影响.
例
let a = Promise.resolve();
a.then(v => Promise.resolve("A")).then(v => console.log(v));
a.then(v => "B").then(v => console.log(v));
Run Code Online (Sandbox Code Playgroud)
直接在Chrome(v 61)控制台中运行时的输出:
B
A.
但是,当点击Run code snippet
按钮时,我会收到订单A
B
.
是否在ES6中为上述示例定义了执行顺序,还是由实现决定?
如果定义了,那么正确的输出应该是什么?
Promise.resolve
指定返回已解决的承诺(令人兴奋,对吧?25.4.4.5、25.4.1.5、25.4.1.3。)。因此每次都会a.then()
立即将作业加入队列(25.4.5.3.1 ,步骤8)。.then()
根据此规范,永远不会返回已履行的承诺(对于一些有趣的事情,请Promise.resolve().then()
在 Chrome 控制台\xc2\xb9 中尝试)。
让\xe2\x80\x99s 将promisea.then(v => Promise.resolve("A"))
及其一些相关的规范状态命名为p1 \xc2\xb2。如上所述,这.then()
会将要调用的作业排队 ( 25.4.2.1 ) 。a.then(v => Promise.resolve("A"))
第一个.then(v => console.log(v))
将对应于 \xe2\x82\x81 的承诺反应附加到待处理承诺p1v => console.log(v)
的履行反应列表中(仍然是 25.4.5.3.1)。
现在队列是:
\n\nv => Promise.resolve("A")
p1现在v => console.log(v)
在其完成反应列表中包含 \xe2\x82\x81
承诺a.then(v => "B")
可以是p2。目前它的工作方式相同。
现在队列是:
\n\nv => Promise.resolve("A")
v => "B"
p1 的v => console.log(v)
履行反应列表中有\xe2\x82\x81
v => console.log(v)
在其完成反应列表中有 \xe2\x82\x82我们已经到达了脚本的结尾。
\n\n当对应于 的第一个作业出队v => Promise.resolve("A")
并被调用时(再次25.4.2.1),在结果中找到athen
(这是重要的部分),导致另一个作业入队(25.4.1.3.2,步骤 12),无论该结果的承诺状态。
现在队列是:
\n\nv => "B"
Promise.resolve("A").then
使用p1 \xe2\x80\x99s [[Resolve]] 和 [[Reject]]进行调用p1 的v => console.log(v)
履行反应列表中有\xe2\x82\x81
v => console.log(v)
在其完成反应列表中有\xe2\x82\x82下一个作业将出列并被调用。结果中未找到可调用对象,因此then
p2立即完成(再次为25.4.1.3.2,步骤 11a),并为每个p2 \xe2\x80\x99s 完成反应排队一个作业。
现在队列如下:
\n\nPromise.resolve("A").then
使用p1 \xe2\x80\x99s [[Resolve]] 和 [[Reject]]进行调用v => console.log(v)
\xe2\x82\x82p1 的v => console.log(v)
履行反应列表中有\xe2\x82\x81
I\xe2\x80\x99m 将在这里停止这一级别的解释,并再次Promise.resolve("A").then
开始整个then
序列。不过,您可以看到这是怎么回事:作业队列是一个队列,并且将产生输出的一个函数在队列中,而另一个函数尚未添加。队列中的\xe2\x80\x99 将首先运行。
正确的输出是 B 后跟 A。
\n\n那么,既然这样,为什么 Chrome 中的答案在一个页面中是错误的呢?它\xe2\x80\x99s 不是一些堆栈溢出片段填充程序;您可以使用一些 HTML 本身或在 Node.js 中重现它。我的猜测是,它\xe2\x80\x99 是一个破坏规范的优化。
\n\n\'use strict\';\r\n\r\nclass Foo extends Promise {}\r\n\r\nlet a = Promise.resolve();\r\na.then(v => Foo.resolve("A")).then(v => console.log(v));\r\na.then(v => "B").then(v => console.log(v));
Run Code Online (Sandbox Code Playgroud)\r\nthenable
这个有趣的脚本的替代定义node --allow_natives_syntax
!
\'use strict\';\n\nconst thenable = p => ({ then: p.then.bind(p) });\n//const thenable = p => p;\n\nlet a = Promise.resolve();\na.then(v => {\n %EnqueueMicrotask(() => {\n %EnqueueMicrotask(() => {\n console.log("A should not have been logged yet");\n });\n });\n\n return thenable(Promise.resolve("A"));\n}).then(v => console.log(v));\na.then(v => "B").then(v => console.log(v));\n
Run Code Online (Sandbox Code Playgroud)\n\n\xc2\xb9 对于后代:它\xe2\x80\x99是 Chrome 61.0.3163.100 中已解决的承诺。
\n \xc2\xb2 That\xe2\x80\x99s 不如规范具体,但这是一个试图描述规范而不是规范的答案。运气好的话,它\xe2\x80\x99 也是正确的。
归档时间: |
|
查看次数: |
471 次 |
最近记录: |