简体   繁体   中英

Sending multiple API request using Promise

How to send multiple API request? so I have this code below

 const productID= [12, 43, 65, 87, 45, 76, 87];
    productID.map(id => {
     API.removeItem(id, (err, response) => {
       if (response.status === 'success') {
           console.log('remove a product');
        }else {
          console.log(err); 
        }
     })
})

The problem is that it doesn't wait for first API request to finish and get the response back, and only removing one item. So basically I wanted this to become synchronous and that's why I use async await to resolve my problem.

async function removeProducts() {
    const productID = [12, 43, 65, 87, 45, 76, 87];
    const result = await Promise.all(productID.map(id => {
        API.removeItem(id, (err, response) => {
            if (response.status === 'success') {
                console.log('remove a product');
            }else {
                console.log(err); 
        }
        });
    }));
}

The result of this is almost the same as the first code snippet, but it this time it was able to remove 2 product items. I want that the next request is made only if the previous request is finished. How can I do that?

The problem with your second attempt is that Promise.all() takes an array of promises as an argument. The Promise.all() function also returns a promise itself that is resolved when every promise in the array passed in is resolved.

The array.map does not return a promise, it returns a new array with the results of every item in the array called with the provided function. Read more about the map function here .

Instead create a wrapper function for the API call that returns a promise.


const productID = [12, 43, 65, 87, 45, 76, 87];

let removeProductID = (id) => {
    return new Promise((resolve, reject) => {
        API.removeItem(id, (err, response) => {
            if (response.status === 'success') {
                console.log('remove a product');
                resolve(response);
            } else {
                console.log(err);
                reject(err);
            }
        })
    });
}

let removeAllProductIDs = async () => {
    for(let id of productID) {
        await removeProductID(id);
    }
}

removeAllProductIDs();

Actually Promise.All() make the parallel request so this is not a solution that you are looking for.

What you need is that yield the result then make another request and so on. For that, you need API.removeItem to return Promise .if it is not then you can wrap this function using Promise API to return Promise.

    async function removeItem(id) {
      return new Promise((resolve, reject) => {
        API.removeItem(id, (err, response) => {
          if (response.status === 'success') {
            resolve("message or data"); // or pass id or anything
          } else {
            console.log(err);
            reject(err)
          }
        })
      })
    }

Now you can use this function to yield the result.

 const productID = [12, 43, 65, 87, 45, 76, 87];
    async function removeProducts() {
       for (let i = 0; i < productID.length; i++) {
            const result = await removeItem(productID[i]); // will return resolved value here
            // sequence
          }
     }
const productID = [12, 43, 65, 87, 45, 76, 87];
function process() {
    if (productID.length == 0) return;

    var id = productID.pop();
    API.removeItem(id, (err, response) => {
       if (response.status === 'success') {
           console.log('remove a product');
           process(); // process next item if success
        } else {
          console.log(err); 
        }
    });
};

process();

Like the other answers, start by promisifying API.removeItem (If your environment is Node.js, you can use util.promisify , otherwise use the Promise constructor as shown in other answers):

const {promisify} = require('util');

const removeItem = promisify(API.removeItem);

Then, if you don't mind pulling in a third party module, you can use async-af (a module I maintain) to loop through the IDs sequentially using an async forEach :

const AsyncAF = require('async-af');

const removeItems = ids => AsyncAF(ids).series.forEach(removeItem);

removeItems([12, 43, 65, 87, 45, 76, 87]);

Alternatively, you can use vanilla JS to loop through the ids sequentially; for instance, here's an implementation using Array.prototype.reduce :

const removeItems = ids => ids.reduce((acc, id) => (
  acc.then(() => removeItem(id))
), Promise.resolve());

removeItems([12, 43, 65, 87, 45, 76, 87]);

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