Typescript/ES7 中异步/等待的有限并行性

IT技术 javascript typescript async-await
2021-02-08 22:04:55

我一直在尝试使用 Typescript,但我现在对如何有效地使用 async/await 有点困惑。

我将一堆记录插入到数据库中,我需要获取每次插入返回的 ID 列表。下面的简化示例在一般情况下有效,但它并不像我想要的那么优雅,而且它是完全顺序的。

async function generatePersons() {
    const names = generateNames(firstNames, lastNames);
    let ids = []
    for (let name of names) {
        const id = await db("persons").insert({
            first_name: name.firstName,
            last_name: name.lastName,
        }).returning('id');
        ids.push(id[0])
    }
    return ids
}

我试图用来map避免ids手动创建列表,但我可以让它工作。

我还想要的是有限数量的并行性。所以我的异步调用应该在达到一定限制的情况下并行发生,例如,我只希望有 10 个打开的请求,但不会更多。

在 Typescript 或 Javascript ES7 中使用 async/await 实现这种有限的并行性是否有一种相当优雅的方法?或者我是否试图让这个功能做一些它不适合的事情?

PS:我知道数据库有批量插入方法,这个例子有点人为,因为我可以使用这些方法来解决这个特定问题。但这让我想知道我没有可用的预定义批量方法的一般情况,例如网络请求

3个回答

Promise.all 将允许您等待所有请求停止完成,而不会阻止它们的创建。

但是,听起来您有时确实想阻止。具体而言,这听起来像你想扼杀在飞行的请求数在任何给定的时间。这是我提出的一些东西(但还没有完全测试!)

async function asyncThrottledMap<T, U>(maxCount: number, array: T[], f: (x: T) => Promise<U>) {
    let inFlight = new Set<Promise<U>>();
    const result: Promise<U>[] = [];

    // Sequentially add a Promise for each operation.
    for (let elem of array) {

        // Wait for any one of the promises to complete if there are too many running.
        if (inFlight.size >= maxCount) {
            await Promise.race(inFlight);
        }

        // This is the Promise that the user originally passed us back.
        const origPromise = f(elem);
        // This is a Promise that adds/removes from the set of in-flight promises.
        const handledPromise = wrap(origPromise);
        result.push(handledPromise);
    }

    return Promise.all(result);

    async function wrap(p: Promise<U>) {
        inFlight.add(p);
        const result = await p;
        inFlight.delete(p);
        return result;
    }
}

上面inFlight是一组当前正在进行的操作。

result是阵列包裹 Promise秒。这些包装好的Promise中的每一个基本上都是从操作集中添加或删除inFlight操作。如果有太多的飞行中操作,那么这将Promise.race用于完成任何一个飞行中操作。

希望这有帮助。

天哪,忘记我在说什么了。我不得不考虑这个有时await是 s 有时不是第一个的异步循环,而名称“ wrap”使我走上了错误的轨道。这确实应该奏效。
2021-04-05 22:04:55

查看async-parallel库,它提供了各种帮助函数,可以轻松执行并行操作。使用这个库,你的代码可能看起来像这样......

async function generatePersons(): Promise<number[]> {
    const names = generateNames(firstNames, lastNames);
    return await Parallel.map(names, async (name) => 
        await db("persons").insert({
            first_name: name.firstName,
            last_name: name.lastName,
        }).returning('id'));
}

如果您想将实例数量限制为一次说四个,您可以简单地执行以下操作...

Parallel.concurrency = 4;
不,并发也可以在优先于全局设置的函数级别指定。示例:await Parallel.map(..., ..., {concurrency: 4})。默认并发为零,这是无限的。
2021-03-31 22:04:55

是否有一种相当优雅的方法可以在 Typescript 或 Javascript ES7 中使用 async/await 实现这种有限的并行性

您将不得不使用Promise.all. 即收集数组中的所有Promise和await Promise.all([all,the,stuff])

更多的

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all