2016-08-28 49 views
4

我一直在使用Typescript进行一些实验,但现在有点卡在如何有效使用异步/等待。与Typescript/ES7中异步/等待的并行性有限

我插入一堆记录到数据库中,我需要得到每个插入返回的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中,是否有一种合理优雅的方式来实现异步/等待的这种有限并行?或者我是否试图让这个功能做一些它不是为了什么? PS:我知道有数据库的批量插入方法,这个例子有点人为,因为我可以使用这些来解决这个特定的问题。但是这让我想到了我没有预定义批量方法的一般情况,例如与网络请求

+0

“并行”是2时执行上下文同时运行(可能在2个不同的计算单元上)。你不能在JS中获得。 – zerkms

+0

[由于非平行等待承诺导致速度减慢](http://stackoverflow.com/q/24193595/1048572)? – Bergi

+0

看看[使用异步/等待与forEach循环](http://stackoverflow.com/q/37576685/1048572) – Bergi

回答

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 s。这些包装承诺中的每一个基本上都会增加或删除inFlight操作集中的操作。如果有太多的飞行中操作,那么这将使用Promise.race来完成任何一项正在进行的操作。

希望有帮助。

+0

哦,我的,忘了我在说什么。我不得不绕过这个有时候“等待”,有时不是第一次的异步循环,名字“wrap”导致我走错了路。这应该确实。 – Bergi

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; 
+0

您是否必须在全局设置'Parallel.concurrency'? – Bergi

+0

不,也可以在优先于全局设置的功能级别指定并发性。示例:await Parallel.map(...,...,{concurrency:4})。默认并发性为零,无限制。 –