从生成器生成的承诺在等待时未同时解析



我正在使用生成器函数来模拟可迭代的任务队列:

function* taskQueue() {
for(let i=0; i<10; i++) {
yield new Promise((resolve) => {
setTimeout(() => resolve(i), (11 - i)*1000)
})
}
}

超时应导致承诺以相反的顺序解析(假设所有承诺同时启动),最长的在 11 秒内完成。

遍历 promise,并使用 Promise.then(),代码的长度 要完成的最长超时(11 秒):

function then() {
let q = taskQueue();
for(i of q) {
i.then(console.log)
}
}

但是,如果我等待承诺,那么它们会按顺序解析,并且需要线性时间(66 秒)才能完成:

async function awaiting() {
let q = taskQueue();
for(i of q) {
let n = await i;
console.log(n);
}
}

这似乎是因为在前一个承诺解析之前,taskQueue 没有产生下一个承诺,因为如果我将它们推送到数组上然后等待,代码将在 11 秒内执行:

async function awaiting2() {
let q = taskQueue();
let tasks = [];
for(i of q) {
tasks.push(i);
}
for(i of tasks) {
let n = await i;
console.log(n);
}
}

那么,为什么在 then() 的情况下同时解析承诺,而在 awaiting() 的情况下却没有呢?

这是因为Promises自然是异步的,因为在程序的其余部分将继续执行,无论 Promise 处于什么状态(挂起、已解决、错误)。

通过使用async关键字,您告诉功能块等待使用await关键字指定的每个 Promise,以等待该 Promise 解析,然后再继续执行,从而使该功能块同步。

通过在 Promise 上调用.then()方法,可以使 Promise 执行保持异步状态,但无论程序中发生什么其他事情,都会在 Promise 执行完成时调用.then()

可以调整第一个示例中的代码,以输出与使用asycn/await的代码在使用递归的模式中使用.next().then()相同的结果"一个碰巧引用自身的非终止过程"。递归的边界是什么?

function* taskQueue() {
for (let i = 0; i < 10; i++) {
yield new Promise((resolve) => {
setTimeout(() => resolve(i), (11 - i) * 1000)
})
}
}
const queue = taskQueue();
const awaiting = ({value:promise, done}, q) => 
done ? {done} : promise.then(data => (console.log(data), awaiting(q.next(), q)));
awaiting(queue.next(), queue)
.then(console.log)
.catch(console.error)

最新更新