如何交错/合并异步迭代?

编程入门 行业动态 更新时间:2024-10-25 13:16:17
本文介绍了如何交错/合并异步迭代?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

假设我有一些像这样的asnyc可迭代对象:

Suppose I have some asnyc iterable objects like this:

// 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! '); }, };

现在,假设我可以像这样连接它们:

Now, suppose I can concat them like this:

const abcs = async function * () { yield * a; yield * b; yield * c; };

产生的(前9个)项目将是:

The (first 9) items yielded will be:

(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 以不同的速度屈服,我想尽快收益。

But imagine that I do not care about the order, that a, b and c yield at different speeds, and that I want to yield as quickly as possible.

如何重写此循环以便 x s是否尽快屈服,无视秩序?

How can I rewrite this loop so that xs are yielded as soon as possible, ignoring order?

也可能 a , b 或 c 是无限序列,因此解决方案不能要求将所有元素缓冲到数组中。

It is also possible that a, b or c are infinite sequences, so the solution must not require all elements to be buffered into an array.

推荐答案

没有办法用循环语句写这个。 async / await 代码总是按顺序执行,以便同时执行需要直接使用promise combinators的事情。对于普通的承诺,有 Promise.all ,对于异步迭代器,什么都没有(还),所以我们需要自己编写它:

There is no way to write this with a loop statement. async/await code always executes sequentially, to do things concurrently you need to use promise combinators directly. For plain promises, there's Promise.all, for async iterators there is nothing (yet) so we need to write it on our own:

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; }

请注意组合不支持将值传递到 next 或通过 .throw 或 .return 。

Notice that combine does not support passing values into next or cancellation through .throw or .return.

您可以将其称为

(async () => { for await (const x of combine([a, b, c])) { console.log(x); } })().catch(console.error);

更多推荐

如何交错/合并异步迭代?

本文发布于:2023-07-27 00:21:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1219207.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:迭代

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!