I'm using the axios promise library, but my question applies more generally I think. Right now I'm looping over some data and making a single REST call per iteration.
As each call completes I need to add the return value to an object. At a high level, it looks like this:
var mainObject = {}; myArrayOfData.forEach(function(singleElement){ myUrl = singleElement.webAddress; axios.get(myUrl) .then(function(response) { mainObject[response.identifier] = response.value; }); }); console.log(convertToStringValue(mainObject));
What's happening of course is when I call console.log
the mainObject
doesn't have any data in it yet, since axios is still reaching out. What's a good way of dealing with this situation?
Axios does have an all
method along with a sister spread
one, but they appear to be of use if you know ahead of time how many calls you'll be making, whereas in my case I don't know how many loop iterations there will be.
To use Javascript promises in a for loop, use async / await . This waits for each promiseAction to complete before continuing to the next iteration in the loop. In this guide, you learn how async/await works and how it solves the problem of using promises in for loops.
async and await Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
The keyword await is used to wait for a Promise. It can only be used inside an async function. This keyword makes JavaScript wait until that promise settles and returns its result.
all() The Promise. all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will fulfill when all of the input's promises have fulfilled, or if the input iterable contains no promises.
You need to collect all of your promises in an array and then use Promise.all
:
// Example of gathering latest Stack Exchange questions across multiple sites // Helpers for example const apiUrl = 'https://api.stackexchange.com/2.2/questions?pagesize=1&order=desc&sort=activity&site=', sites = ['stackoverflow', 'ubuntu', 'superuser'], myArrayOfData = sites.map(function (site) { return {webAddress: apiUrl + site}; }); function convertToStringValue(obj) { return JSON.stringify(obj, null, '\t'); } // Original question code let mainObject = {}, promises = []; myArrayOfData.forEach(function (singleElement) { const myUrl = singleElement.webAddress; promises.push(axios.get(myUrl)); }); Promise.all(promises).then(function (results) { results.forEach(function (response) { const question = response.data.items[0]; mainObject[question.question_id] = { title: question.title, link: question.link }; }); console.log(convertToStringValue(mainObject)); });
<script src="https://unpkg.com/[email protected]/dist/axios.min.js"></script>
It's described in axios docs (Performing multiple concurrent requests section).
Before May 2020 it was possible to do with axios.all(), which is now deprecated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With