假设我有一些像这样的asnyc可迭代对象:
// Promisified sleep function
const sleep = ms => new Promise((resolve, reject) => {
setTimeout(() => resolve(ms), ms);
});
const a = {
[Symbol.asyncIterator]: async function * () {
yield 'a';
await sleep(1000);
yield 'b';
await sleep(2000);
yield 'c';
},
};
const b = {
[Symbol.asyncIterator]: async function * () {
await sleep(6000);
yield 'i';
yield 'j';
await sleep(2000);
yield 'k';
},
};
const c = {
[Symbol.asyncIterator]: async function * () {
yield 'x';
await sleep(2000);
yield 'y';
await sleep(8000);
yield 'z';
await sleep(10000);
throw new Error('You have gone too far! ');
},
};
现在,假设我可以像这样连接它们:
const abcs = async function * () {
yield * a;
yield * b;
yield * c;
};
产生的(前9个)项目将是:
(async () => {
const limit = 9;
let i = 0;
const xs = [];
for await (const x of abcs()) {
xs.push(x);
i++;
if (i === limit) {
break;
}
}
console.log(xs);
})().catch(error => console.error(error));
// [ 'a', 'b', 'c', 'i', 'j', 'k', 'x', 'y', 'z' ]
但是想象一下,我不关心顺序,a,b和c以不同的速度屈服,并且我想尽可能快地屈服.
我怎样才能重写这个循环,以便尽快产生xs,忽略顺序?
a,b或c也可能是无限序列,因此解决方案不能要求将所有元素缓冲到数组中.
解决方法:
没有办法用循环语句写这个. async / await代码总是按顺序执行,要同时执行操作,需要直接使用promise combinators.对于普通的承诺,有Promise.all,对于异步迭代器,什么都没有(还),所以我们需要自己编写它:
async function* combine(iterable) {
const asyncIterators = Array.from(iterable, o => o[Symbol.asyncIterator]());
const results = [];
let count = asyncIterators.length;
const never = new Promise(() => {});
function getNext(asyncIterator, index) {
return asyncIterator.next().then(result => ({
index,
result,
}));
}
const nextPromises = asyncIterators.map(getNext);
while (count) {
const {index, result} = await Promise.race(nextPromises);
if (result.done) {
nextPromises[index] = never;
results[index] = result.value;
count--;
} else {
nextPromises[index] = getNext(asyncIterators[index], index);
yield result.value;
}
}
return results;
}
请注意,combine不支持将值传递到next或通过.throw或.return取消.
你可以这样称呼它
(async () => {
for await (const x of combine([a, b, c])) {
console.log(x);
}
})().catch(console.error);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。