链式承诺如何在微任务队列中排队
how are chained promises queued in microtasks queue
(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 中,并发模型是事件循环,其中单个线程从队列中执行回调。
在第一个片段中,发生了以下情况。
- 由于承诺已重新提交,
.then
将回调 () => a = 1
添加到队列中。
() => b = 2
已添加到队列中。
- await1
() => console.log(a); console.log(b)
2后的代码加入队列
- 第1步的回调是运行,
a
设置为1
b
设置为 2
a
和 b
已记录。
由于设置变量发生在打印它们之前,因此您会同时看到 1 和 2。
在第二个片段中:
- 回调
() => a = 1
由 .then
添加到队列中
- 第一个
.then
returns 一个新的承诺,尚未解决,因为第一个回调尚未 运行。然后第二个 .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”在 Node 12 中提前两步出现的原因。
- 您可以拥有简化的心智模型,
await
将其余代码转换为回调。
- 事实上"the rest of the code"也解析了异步函数创建的promise。
- 呵呵,所以
.then
和await
毕竟不一样
(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 中,并发模型是事件循环,其中单个线程从队列中执行回调。
在第一个片段中,发生了以下情况。
- 由于承诺已重新提交,
.then
将回调() => a = 1
添加到队列中。 () => b = 2
已添加到队列中。- await1
() => console.log(a); console.log(b)
2后的代码加入队列 - 第1步的回调是运行,
a
设置为1 b
设置为 2a
和b
已记录。
由于设置变量发生在打印它们之前,因此您会同时看到 1 和 2。
在第二个片段中:
- 回调
() => a = 1
由.then
添加到队列中
- 第一个
.then
returns 一个新的承诺,尚未解决,因为第一个回调尚未 运行。然后第二个.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”在 Node 12 中提前两步出现的原因。
- 您可以拥有简化的心智模型,
await
将其余代码转换为回调。 - 事实上"the rest of the code"也解析了异步函数创建的promise。
- 呵呵,所以
.then
和await
毕竟不一样