首页 > 解决方案 > 在 Typescript 中运行一批 Promise

问题描述

我的 Typescript 项目中有一系列 Promises。

大多数时候,我使用 Promise.all() 来并行执行所有这些:

let promises:Array<Promise<string>> = ....
Promise.all(promises)
  .then(results:Array<string> => ....)
  .catch(error => ....)

我必须通过以 3 的并发运行来执行一系列 Promise 来减少背压。

我想保持没有依赖关系,但如果你有一个通过 dep 的解决方案,请随意。


我尝试使用es6-promise-pool但我似乎还没有为 Typescript 准备好

import PromisePool = require('es6-promise-pool')
const promiseProducer = () => {
    if (commands.length > 0) {
        return commands.shift()
    } else {
        return null
    }
}
let concurrency = 3;
let pool = new PromisePool(promiseProducer, concurrency)

此表达式不可构造。类型 'typeof import("..../node_modules/es6-promise-pool/es6-promise-pool")' 没有构造签名。


我已经根据@jfriend00 的评论实现了mapConcurrent()函数。

function mapConcurrent(items: Array<any>, maxConcurrent: number, fn: any): Promise<Array<any>> {
    let index = 0;
    let inFlightCntr = 0;
    let doneCntr = 0;
    let results = new Array(items.length);
    let stop = false;
    return new Promise((resolve, reject) => {
        const runNext = () => {
            let i = index;
            ++inFlightCntr;
            fn(items[index], index++).then(function (val: any) {
                ++doneCntr;
                --inFlightCntr;
                results[i] = val;
                run();
            }, function (err: any) {
                stop = true;
                reject(err);
            });
        }
        const run = () => {
            while (!stop && inFlightCntr < maxConcurrent && index < items.length) {
                runNext();
            }
            if (doneCntr === items.length) {
                resolve(results);
            }
        }
        run();
    });
}

然后我能够按预期运行承诺

let array = [1,2,3,4,5,6,7,8,9,10]
const maxConcurrency = 3
mapConcurrent(array, maxConcurrency , (index: number) => myPromise(index))
    .then((results: Array<any>) => {
        //... do stuff with results ...
     }).catch(error => { reject(error) })

根据 Typescript,只缺少一个东西,有没有办法为 Promise 结果获取 Promise 类型的数组?

如果我的 promise 的类型是 <{id:string}>,我们可以得到类型为 Array<{id:string}> 的结果吗?

实际上 mapConcurrent() 只解析类型 Array

标签: typescriptconcurrencypromisebackpressure

解决方案


随着打字

function mapConcurrent<T>(items: Array<string>, maxConcurrent: number, fn: (item: string) => Promise<T>): Promise<Array<T>> {
        let index = 0;
        let inFlightCntr = 0;
        let doneCntr = 0;
        let results = new Array(items.length);
        let stop = false;
        return new Promise((resolve, reject) => {
            const runNext = () => {
                let i = index;
                ++inFlightCntr;
                fn(items[index])
                    .then(result => {
                        ++doneCntr;
                        --inFlightCntr;
                        results[i] = result;
                        run();
                    })
                    .catch(error => {
                        stop = true;
                        reject(error);
                    });
                index++
            }
            const run = () => {
                while (!stop && inFlightCntr < maxConcurrent && index < items.length) {
                    runNext();
                }
                if (doneCntr === items.length) {
                    resolve(results);
                }
            }
            run();
        });
    }

推荐阅读