为什么这个异步函数在它之前定义的等效 Promise.then 链之前执行?
Why does this async function execute before the equivalent Promise.then chain defined before it?
我有以下代码:
var incr = num => new Promise(resolve => {
resolve(num + 1);
});
var x = incr(3)
.then(resp => incr(resp))
.then(resp => console.log(resp));
async function incrTwice(num) {
const first = await incr(num);
const twice = await incr(first);
console.log(twice);
}
incrTwice(6);
我认为(也许是错误的)显示了实现相同功能的两种等效方法:首先通过链接承诺,其次使用 async/await.
的语法糖
我希望首先打印 console.log 的承诺链解决方案,然后是异步函数,但是异步函数 console.log 首先打印承诺链解决方案。
我的逻辑是这样的:
x
s 初始 resolve 将在处理声明时首先出现在微任务队列中
- 在
x
和 incrTwice
的声明之间堆栈为空,这将导致微任务队列被刷新(导致承诺链完成)
- x 先打印
incrTwice
定义
incrTwice
在 await
的微任务队列上执行排队,最终打印到控制台
- incrTwice 打印第二个
显然我哪里有误会,有人能指出我错在哪里吗?
你的想法是可以理解和合乎逻辑的。观察到的行为的原因与 Promise API 中内置的保证之一有关,即 promises 在执行中始终是异步的,即使它们执行同步操作(如立即解决承诺)。从技术上讲,这意味着在 当前 运行 完成之前,不会调用承诺的回调。
作为 MDN puts it:
Callbacks will never be called before the completion of the current run of the JavaScript event loop.
所以:
Promise.resolve(10).then(value => console.log(value));
console.log(20); //20, 10 - NOT 10, 20
我在我的承诺指南中对此进行了介绍,可以是 found here。
首先,我要指出的是,你永远不应该争论独立承诺链的执行顺序。有两个异步调用,它们彼此不依赖,但 运行 同时进行,因此它们应该 总是 以任意顺序完成。
仅使用立即解决承诺的玩具示例使此顺序依赖于微任务排队语义而不是实际的异步任务,这使其成为纯粹的学术练习(其在规范中为 result is subject to changes)。
总之,先解开大家的误会吧:
the stack is empty between the declaration of x
and incrTwice
which would cause the microtask queue to be flushed
不,只有在所有用户代码运行完成后,堆栈才会变空。堆栈上仍然存在 <script>
元素的全局执行上下文。在所有同步代码(incr = …
、x = incr(3).…
和 incrTwice(6)
)完成之前,不会执行任何微任务。
I believe [the code] shows two equivalent ways to achieve the same functionality: first by chaining promises and second with the syntactic sugar of async/await.
不完全是。当取消嵌套从第一个 .then(…)
处理程序返回的 incr(resp)
承诺时,.then()
链接有一个额外的解析步骤。要使它的行为与 incrTwice
中的 await
ed 承诺完全相同,您需要编写
incr(3).then(resp =>
incr(resp).then(resp =>
console.log(resp)
)
);
如果这样做,您实际上会按照启动两个承诺链的顺序获得 console
日志,因为它们将执行相同数量的微任务,直到 console.log()
已执行。
有关详细信息,请参阅 , , , What is the difference between returned Promise?,
我有以下代码:
var incr = num => new Promise(resolve => {
resolve(num + 1);
});
var x = incr(3)
.then(resp => incr(resp))
.then(resp => console.log(resp));
async function incrTwice(num) {
const first = await incr(num);
const twice = await incr(first);
console.log(twice);
}
incrTwice(6);
我认为(也许是错误的)显示了实现相同功能的两种等效方法:首先通过链接承诺,其次使用 async/await.
的语法糖我希望首先打印 console.log 的承诺链解决方案,然后是异步函数,但是异步函数 console.log 首先打印承诺链解决方案。
我的逻辑是这样的:
x
s 初始 resolve 将在处理声明时首先出现在微任务队列中- 在
x
和incrTwice
的声明之间堆栈为空,这将导致微任务队列被刷新(导致承诺链完成)- x 先打印
incrTwice
定义incrTwice
在await
的微任务队列上执行排队,最终打印到控制台- incrTwice 打印第二个
显然我哪里有误会,有人能指出我错在哪里吗?
你的想法是可以理解和合乎逻辑的。观察到的行为的原因与 Promise API 中内置的保证之一有关,即 promises 在执行中始终是异步的,即使它们执行同步操作(如立即解决承诺)。从技术上讲,这意味着在 当前 运行 完成之前,不会调用承诺的回调。
作为 MDN puts it:
Callbacks will never be called before the completion of the current run of the JavaScript event loop.
所以:
Promise.resolve(10).then(value => console.log(value));
console.log(20); //20, 10 - NOT 10, 20
我在我的承诺指南中对此进行了介绍,可以是 found here。
首先,我要指出的是,你永远不应该争论独立承诺链的执行顺序。有两个异步调用,它们彼此不依赖,但 运行 同时进行,因此它们应该 总是 以任意顺序完成。
仅使用立即解决承诺的玩具示例使此顺序依赖于微任务排队语义而不是实际的异步任务,这使其成为纯粹的学术练习(其在规范中为 result is subject to changes)。
总之,先解开大家的误会吧:
the stack is empty between the declaration of
x
andincrTwice
which would cause the microtask queue to be flushed
不,只有在所有用户代码运行完成后,堆栈才会变空。堆栈上仍然存在 <script>
元素的全局执行上下文。在所有同步代码(incr = …
、x = incr(3).…
和 incrTwice(6)
)完成之前,不会执行任何微任务。
I believe [the code] shows two equivalent ways to achieve the same functionality: first by chaining promises and second with the syntactic sugar of async/await.
不完全是。当取消嵌套从第一个 .then(…)
处理程序返回的 incr(resp)
承诺时,.then()
链接有一个额外的解析步骤。要使它的行为与 incrTwice
中的 await
ed 承诺完全相同,您需要编写
incr(3).then(resp =>
incr(resp).then(resp =>
console.log(resp)
)
);
如果这样做,您实际上会按照启动两个承诺链的顺序获得 console
日志,因为它们将执行相同数量的微任务,直到 console.log()
已执行。
有关详细信息,请参阅