简体   繁体   中英

Sequential execution of Promise.all

Hi I need to execute promises one after the other how do I achieve this using promise.all any help would be awesome. Below is the sample of my code I am currently using but it executes parallel so the search will not work properly

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);
        }
    });
}

I looked up in google and saw the reduce will help I would appreciate any help on how to convert this to reduce or any method you suggest (Concurrency in .map did not work)

the Promises unfortunatelly does not allow any control of their flow. It means -> once you create new Promise, it will be doing its asynchronous parts as they like.

The Promise.all does not change it, its only purpose is that it checks all promises that you put into it and it is resolved once all of them are finished (or one of them fail).

To be able to create and control asynchronous flow, the easiest way is to wrap the creation of Promise into function and create some kind of factory method. Then instead of creating all promises upfront, you just create only one promise when you need it, wait until it is resolved and after it continue in same behaviour.

 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: It is also possible without async/await using standard promise-chains, but it requires to be implemented with recursion.

If anyone else cares about ESLint complaining about the use of "for" and the "no await in loop" here is a typescript ESLint friendly version of the above answer:

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))];
}

You can then just replace Promise.all by runPromisesSequentially .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM