javascript - 链式承诺如何在微任务队列中排队
问题描述
(async function() {
var a,b;
function flush(){
return new Promise(res => {
res(123)
})}
Promise.resolve().then(() => a = 1)
Promise.resolve().then(() => b = 2)
await flush();
console.log(a)
console.log(b)
})()
在此代码段中, 和 的值a
被b
记录在控制台中。
(async function() {
var a;
var b;
function flush(){
return new Promise(res => {
res(123)
})}
Promise.resolve().then(() => a = 1).then(() => b = 2)
await flush();
console.log(a)
console.log(b)
})()
在这种情况下,值a
被记录为 1,而b
未定义。
(async function() {
var a;
var b;
function flush(){
return new Promise(res => {
setTimeout(res)
})}
Promise.resolve().then(() => a = 1).then(() => b = 2)
await flush();
console.log(a)
console.log(b)
})()
这给出了与第一个片段相同的结果,值为a
1 和b
2
我想了解,为什么 Promise 链接的行为与多个单独的 Promise 不同
PS:我对微任务队列和事件循环有一个基本的了解。
解决方案
运行节点 12.3.1,我可以在更改setTimeout(res(123))
为setTimeout(() => res(123))
.
在 JavaScript 中,并发模型是事件循环,其中单个线程执行队列中的回调。
在第一个片段中,发生了以下情况。
- 由于 promise 被解析,
.then
所以将回调添加() => a = 1
到队列中。 () => b = 2
被添加到队列中。- await 1
() => console.log(a); console.log(b)
2之后的代码被添加到队列中。 - 运行第 1 步中的回调,
a
设置为 1 b
设置为 2a
并b
记录下来。
由于设置变量是在打印它们之前发生的,因此您会看到 1 和 2。
在第二个片段中:
- 回调
() => a = 1
被添加到队列中.then
- 第一个
.then
返回一个未解决的新承诺,因为第一个回调尚未运行。然后 second.then
附加() => b = 2
到未决的承诺。 - 等待之后的代码
() => console.log(a); console.log(b)
被添加到队列中。 - 回调
() => a = 1
运行,并履行在步骤 2 中创建的承诺。这会导致() => b = 2
被添加到队列中。 a
并b
记录下来。b = 2
已运行,但这发生在b
, 被undefined
打印之后。
然而,在 Firefox 中,所有三个片段的输出都是相同的。我设法通过添加一个async
.
Promise.resolve().then(async () => a = 1).then(() => b = 2)
这是一个显示相同问题的简化版。在 Node 中为 1 5 2 3 4,但在 Firefox 中为 1 2 3 5 4。
(async function() {
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => console.log(3))
.then(() => console.log(4))
await Promise.resolve()
console.log(5)
})()
但是,如果您将 更改await
为.then
,
Promise.resolve().then(() => console.log(5))
你在两个平台上都得到 1 5 2 3 4。3
为什么?我用谷歌搜索发现:https ://v8.dev/blog/fast-async
节点 12 使用 优化了一些额外的步骤await
,这些步骤以前需要一个额外的一次性承诺和两个额外的小标记。这似乎是“5”在节点 12 中提前两步出现的原因。
- 您可以拥有
await
将其余代码转换为回调的简化心智模型。 - 事实上,“其余代码”也解决了异步函数创建的承诺。
- 呵呵,so
.then
和await
毕竟是不同的。
推荐阅读
- kotlin - requireNotNull 与确定运算符!在科特林
- sql - 生成一个行号并在 oracle 中每五个客户重复一次
- laravel - laravel 5 ajax post 500(内部服务器错误)
- c# - 为 episerver 编写动态 css 值 inview
- wso2 - 如何在没有 200 错误的情况下发送邮件 WSO2 迭代调用
- angular - Angular 6 - 英雄之旅 - getHero - 错误 404
- hibernate - Hibernate JPQL 性能差异
- javascript - 检索访问令牌 reddit API
- sql - Eloquent Laravel:whereHas 没有选择模型表
- javafx - JavaFX 程序设计