等待单一承诺与异步迭代器的异步解析顺序
Async resolution order for await single promise vs async iterators
所以这是基于我在开发一个简化异步生成器或迭代器的包时的发现。
通常 promise 的执行顺序由它被调用的时间决定,这意味着以下内容是正确的(在 Chrome & Node on Windows & Mac)。
let resolve, promise = new Promise(r => resolve = r);
(async () => {
await promise
console.log('1st')
})();
(async () => {
await promise
console.log('2nd')
})();
resolve();
但是,在处理异步生成器或迭代器时不遵守此顺序
let resolve, promise = new Promise(r => resolve = r);
async function* generator() {
yield promise
}
(async () => { // regular promise
await promise
console.log('1st')
})();
(async () => { // promise generator
for await (let _ of generator())
console.log('3rd (should be 2nd)')
})();
(async () => { // promise iterator
for await (let _ of [promise])
console.log('4th (should be 3rd)')
})();
(async () => { // regular promise again
await promise
console.log('2nd (should be 4th)')
})();
resolve();
我不确定 "execution /resolution order" 是否是正确的术语,但是这个顺序有保证吗?有什么办法可以在节点或浏览器程序中保证这个顺序吗?
保证解析顺序:
25.6.1.8 TriggerPromiseReactions ( reactions, argument )
[...]
For each reaction in reactions, in original insertion order, do
a. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, << reaction, arguments >>)
要了解迭代器的运行情况,请查看以下代码片段:
let resolve, promise = new Promise(r => resolve = r);
let chained = promise.then(it => Promise.resolve());
(async () => {
await chained;
console.log("2nd");
})();
(async () => { // regular promise
await promise
console.log('1st')
})();
resolve();
如您所见,一个 Promise 在另一个 Promise 解决时得到解决将需要两个微滴。
这就是异步迭代器中发生的事情。当您调用 .next
时,将返回一个 Promise 并将其存储在迭代器内部队列中。与此同时,异步生成器函数的执行还在继续。然后,当异步迭代器 yields
(在您的情况下,在一个微滴答之后),它解决了队列中的下一个承诺。由于 promise 解决是另一个微任务,因此总共需要两个 ticks。
resolve();
// 1 microtick
await promise; // generators await yielded promises implicitly
yield;
// 1 microtick
for await(const _ of iterator)
所以这是基于我在开发一个简化异步生成器或迭代器的包时的发现。
通常 promise 的执行顺序由它被调用的时间决定,这意味着以下内容是正确的(在 Chrome & Node on Windows & Mac)。
let resolve, promise = new Promise(r => resolve = r);
(async () => {
await promise
console.log('1st')
})();
(async () => {
await promise
console.log('2nd')
})();
resolve();
但是,在处理异步生成器或迭代器时不遵守此顺序
let resolve, promise = new Promise(r => resolve = r);
async function* generator() {
yield promise
}
(async () => { // regular promise
await promise
console.log('1st')
})();
(async () => { // promise generator
for await (let _ of generator())
console.log('3rd (should be 2nd)')
})();
(async () => { // promise iterator
for await (let _ of [promise])
console.log('4th (should be 3rd)')
})();
(async () => { // regular promise again
await promise
console.log('2nd (should be 4th)')
})();
resolve();
我不确定 "execution /resolution order" 是否是正确的术语,但是这个顺序有保证吗?有什么办法可以在节点或浏览器程序中保证这个顺序吗?
保证解析顺序:
25.6.1.8 TriggerPromiseReactions ( reactions, argument )
[...]
For each reaction in reactions, in original insertion order, do
a. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, << reaction, arguments >>)
要了解迭代器的运行情况,请查看以下代码片段:
let resolve, promise = new Promise(r => resolve = r);
let chained = promise.then(it => Promise.resolve());
(async () => {
await chained;
console.log("2nd");
})();
(async () => { // regular promise
await promise
console.log('1st')
})();
resolve();
如您所见,一个 Promise 在另一个 Promise 解决时得到解决将需要两个微滴。
这就是异步迭代器中发生的事情。当您调用 .next
时,将返回一个 Promise 并将其存储在迭代器内部队列中。与此同时,异步生成器函数的执行还在继续。然后,当异步迭代器 yields
(在您的情况下,在一个微滴答之后),它解决了队列中的下一个承诺。由于 promise 解决是另一个微任务,因此总共需要两个 ticks。
resolve();
// 1 microtick
await promise; // generators await yielded promises implicitly
yield;
// 1 microtick
for await(const _ of iterator)