Promise.all 的顺序执行

Posted

技术标签:

【中文标题】Promise.all 的顺序执行【英文标题】:Sequential execution of Promise.all 【发布时间】:2019-07-18 22:08:50 【问题描述】:

您好,我需要一个接一个地执行承诺,如何使用 Promise 来实现这一点。任何帮助都会很棒。下面是我目前正在使用的代码示例,但它是并行执行的,因此搜索将无法正常工作

public testData: any = (req, res) => 
    // This method is called first via API and then promise is triggerd 
    var body = req.body;

    // set up data eg 2 is repeated twice so insert 2, 5 only once into DB
    // Assuming we cant control the data and also maybe 3 maybe inside the DB
    let arrayOfData = [1,2,3,2,4,5,5];

    const promises = arrayOfData.map(this.searchAndInsert.bind(this));

    Promise.all(promises)
        .then((results) => 
            // we only get here if ALL promises fulfill
            console.log('Success', results);
            res.status(200).json( "status": 1, "message": "Success data" );
        )
        .catch((err) => 
            // Will catch failure of first failed promise
            console.log('Failed:', err);
            res.status(200).json( "status": 0, "message": "Failed data" );
        );


public searchAndInsert: any = (data) => 
    // There are database operations happening here like searching for other
    // entries in the JSON and inserting to DB
    console.log('Searching and updating', data);
    return new Promise((resolve, reject) => 
        // This is not an other function its just written her to make code readable
        if(dataExistsInDB(data) == true)
            resolve(data);
         else 
            // This is not an other function its just written her to make code readable
            insertIntoDB(data).then() => resolve(data);
        
    );

我在 google 中查找并看到 reduce 会有所帮助,我将不胜感激有关如何将其转换为 reduce 或您建议的任何方法的任何帮助(.map 中的并发不起作用)

【问题讨论】:

您是否尝试过async await 来解决您的问题。 我该怎么做才能分享任何东西 看看这个链接意味着我会在你现有的代码中寻找问题。 javascript.info/async-await 避免Promise constructor antipattern 中的searchAndInsert Resolve promises one after another (i.e. in sequence)?的可能重复 【参考方案1】:

不幸的是,Promises 不允许对其流程进行任何控制。这意味着 -> 一旦你创建了新的 Promise,它将按照他们喜欢的方式执行其异步部分。

Promise.all 不会更改它,它的唯一目的是检查您放入其中的所有承诺,并在所有承诺完成后解决(或其中一个失败)。

为了能够创建和控制异步流程,最简单的方法是将 Promise 的创建包装到函数中并创建某种工厂方法。然后,您无需预先创建所有 Promise,而是在需要时仅创建一个 Promise,等到它被解决,然后继续以相同的行为。

async function doAllSequentually(fnPromiseArr) 
  for (let i=0; i < fnPromiseArr.length; i++) 
    const val = await fnPromiseArr[i]();
    console.log(val);
  


function createFnPromise(val) 
  return () => new Promise(resolve => resolve(val));


const arr = [];
for (let j=0; j < 10; j++) 
  arr.push(createFnPromise(Math.random()));


doAllSequentually(arr).then(() => console.log('finished'));

PS:使用标准的 Promise 链也可以不使用 async/await,但需要使用递归来实现。

【讨论】:

使用递归不会有问题,但我是 JS 新手,所以任何帮助都会很好 @AkshayVenugopal - 如果您支持 Node 7+,只需使用 async/await,它易于读写。【参考方案2】:

如果有人关心 ESLint 抱怨“for”的使用和“循环中没有等待”,这里是上述答案的 typescript ESLint 友好版本:

async function runPromisesSequentially<T>(promises: Array<Promise<T>>):Promise<Array<T>> 
  if (promises.length === 0) return [];
  const [firstElement, ...rest] = promises;
  return [await firstElement, ...(await runPromisesSequentially(rest))];

然后您可以将Promise.all 替换为runPromisesSequentially

【讨论】:

以上是关于Promise.all 的顺序执行的主要内容,如果未能解决你的问题,请参考以下文章

多个请求执行完再执行下一个方法(vue Promise.all用法)

Promise.all:解析值的顺序

Promise 异步函数顺序执行

关于Promise.all

js Promise 等待多个异步操作执行完再去做一些操作

es6 promise.all()