我一直在玩异步生成器,试图制作一个“承诺排序”生成器,它接受一系列承诺,并按照它们解决或拒绝的顺序一个接一个地产生承诺。所以像:
async function* orderProms(prom_arr) {
// Make a copy so the splices don't mess it up.
const proms = [...prom_arr];
while (proms.length) {
// Tag each promise with it's index, so that we can remove it for the next loop.
const {prom, index} = await Promise.race(proms.map((prom, index) => prom.then(
() => ({prom, index}),
() => ({prom, index})
)));
proms.splice(index, 1);
yield prom;
}
}
像这样使用这个生成器的想法:
const resAfter = (val, delay) => new Promise(res => setTimeout(() => res(val), delay));
const rejAfter = (val, delay) => new Promise((_, rej) => setTimeout(() => rej(val), delay));
const promises = [
resAfter("Third", 3000),
resAfter("First", 1000),
rejAfter("Second", 2000), // NOTE: this one rejects!
];
(async () => {
let ordered = orderProms(promises);
let done = false;
for (let next_promise = ordered.next(); !done; next_promise = ordered.next()) {
const next = await next_promise
.catch(err => ({done: false, value: `Caught error: ${err}`}));
done = next.done;
if (!done) console.log(next.value);
}
})()
但是,我注意到这将达到第二个承诺,然后生成器将停止。似乎是因为拒绝了“第二个”承诺。当被拒绝时,调用生成器将在yield prom
生成器中创建一个异常。prom
但这是我困惑的根源。我不想在这里创建异常,我只想将被拒绝的承诺作为value
迭代器结果的结果。我不希望它被打开。几乎就像这被视为yield await prom;
,但正如您所见,没有await
电话。
这里发生了什么,我怎样才能简单地从这个生成器中产生一个被拒绝的承诺。
这是可运行片段中的上述代码:
async function* orderProms(prom_arr) {
// Make a copy so the splices don't mess it up.
const proms = [...prom_arr];
while (proms.length) {
// Tag each promise with it's index, so that we can remove it for the next loop.
const {prom, index} = await Promise.race(proms.map((prom, index) => prom.then(
() => ({prom, index}),
() => ({prom, index})
)));
proms.splice(index, 1);
yield prom;
}
}
const resAfter = (val, delay) => new Promise(res => setTimeout(() => res(val), delay));
const rejAfter = (val, delay) => new Promise((_, rej) => setTimeout(() => rej(val), delay));
const promises = [
resAfter("Third", 3000),
resAfter("First", 1000),
rejAfter("Second", 2000), // NOTE: this one rejects!
];
(async () => {
let ordered = orderProms(promises);
let done = false;
for (let next_promise = ordered.next(); !done; next_promise = ordered.next()) {
const next = await next_promise
.catch(err => ({done: false, value: `Caught error: ${err}`}));
done = next.done;
if (!done) console.log(next.value);
}
})()