与Typescript / ES7中的async / await有限的并行性

时间:2016-08-28 20:20:40

标签: javascript typescript async-await

我一直在尝试使用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 个答案:

答案 0 :(得分:5)

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来完成任何一个正在进行的操作。

希望这有帮助。

答案 1 :(得分:2)

查看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;

答案 2 :(得分:0)

  

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

您必须使用Promise.all。即收集数组中的所有承诺await Promise.all([all,the,stuff])

更多

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