I am looking to iterate through an array of users (with only the id property set), call an endpoint every two seconds with each id, and store the associated user's name from the response into an updated array.
e.g. update [{ id: 1 }]
to [{ id: 1, name: "Leanne Graham" }]
Here is my code:
const axios = require('axios');
const users = [{ id: 1 }, { id: 2 }, { id: 3 }];
function addNameToUser(user) {
return new Promise((resolve) => {
axios.get(`https://jsonplaceholder.typicode.com/users/${user.id}`)
.then(response => {
user.name = response.data.name
resolve(user);
});
})
}
const requests = users.map((user, index) => {
setTimeout(() => {
return addNameToUser(user);
}, index * 2000);
});
Promise.all(requests).then((updatedArr) => {
console.log(updatedArr);
});
Everything works great without the setTimeout
, but it's important that I only send a request every two seconds. So for three users, I would like to see the result from my Promise.all
log after six seconds or so.
Worth noting: This is not the actual problem I am working on, but the easiest example I could come up with to help highlight the issue.
As I understand, the core of your question is how to space your processing by 2 seconds apart, right?
const users = [{ id: 1 }, { id: 2 }, { id: 3 }];
/* throttledProcess is a function that does your processing spaced by the given interval millisecond */
const throttledProcess = (items, interval) => {
if (items.length == 0) { // stop when there's no more items to process
console.log('ALL DONE')
return
}
console.log('PROCESSING', items[0], Date()) // this is where your http call/update/etc takes place
setTimeout(() => throttledProcess(items.slice(1), interval), // wrap in an arrow function to defer evaluation
interval)
}
throttledProcess(users, 2000) // run process. shows output every 2 seconds
Run this code and every 2 secs, it will log out which user is being processed.
Hope this helps. Cheers,
You need to return a Promise from the map's callback. Since this promise will be resolved by the setTimeout()
, we'll use the Promise constructor.
The resolved timeout promise should return the Axios promise, which will return the result when resolved.
Note: since Axios returns a Promise, we don't need to wrap it with another Promise constructor. See What is the explicit promise construction antipattern and how do I avoid it? question and answers.
const users = [{ id: 1 }, { id: 2 }, { id: 3 }];
const addNameToUser = (user) =>
axios.get(`https://jsonplaceholder.typicode.com/users/${user.id}`)
.then(({ data }) => ({
...user,
name: data.name
}));
const requests = users.map((user, index) =>
new Promise(resolve =>
setTimeout(() => resolve(addNameToUser(user)), index * 2000)
));
Promise.all(requests).then((updatedArr) => {
console.log(updatedArr);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
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