Reputation: 86997
Given the following code which I run in the command line with node fileName.js
it seems to run all the items in the loop and THEN sleep at the end ... sorta like it's all running parallel or something.
I would like the code to block/pause during the setTimeout
instead of just running the function AFTER the setTimeout is complete. Or, use a different method if setTimeout
is the incorrect one, in this use case.
const removeUsers = async () => {
const users = await db.getUsers(); // returns 32 users.
// Split the users up into an array, with 2 users in each 'slot'.
var arrays = [], size = 2;
while (users.length > 0) {
arrays.push(users.splice(0, size));
}
// Now, for each slot, delete the 2 users then pause for 1 sec.
arrays.forEach(a => {
console.log(++counter;);
// Delete 2x users.
a.forEach(async u => {
console.log('Deleting User: ' + u.id);
await 3rdPartyApi.deleteUser({id: u.id});
});
// Now pause for a second.
// Why? 3rd party api has a 2 hits/sec rate throttling.
setTimeout(function () { console.log('Sleeping for 1 sec'); }, 1000);
});
}
and the logs are like this..
1.
Deleting User: 1
Deleting User: 2
2.
Deleting User: 3
Deleting User: 4
3.
...
(sleep for 1 sec)
(sleep for 1 sec)
(sleep for 1 sec)
...
end.
See how the sleep doesn't feel like it blocks.. it just fires off a sleep command which then gets handled after a sec...
This is what I'm really after...
1.
Deleting User: 1
Deleting User: 2
(sleep for 1 sec)
2.
Deleting User: 3
Deleting User: 4
(sleep for 1 sec).
3.
...
end.
Upvotes: 0
Views: 75
Reputation: 225105
This calls a bunch of async
functions. They each return a promise (async
functions always return promises), and those promises are discarded, because Array#forEach
doesn’t do anything with the return value of the function it’s passed.
a.forEach(async u => {
console.log('Deleting User: ' + u.id);
await 3rdPartyApi.deleteUser({id: u.id});
});
This starts a timer and doesn’t even attempt to wait for it.
setTimeout(function () { console.log('Sleeping for 1 sec'); }, 1000);
Split off the timer into a function that returns a promise resolving in the appropriate amount of time (available as Promise.delay
if you’re using Bluebird, which you should be):
const delay = ms =>
new Promise(resolve => {
setTimeout(resolve, ms);
});
and keep everything in one async
function so you’re not discarding any promises:
function* chunk(array, size) {
for (let i = 0; i < array.length;) {
yield array.slice(i, i += size);
}
}
const removeUsers = async () => {
const users = await db.getUsers(); // returns 32 users.
for (const a of chunk(users, 2)) {
console.log(++counter);
// Delete 2x users.
for (const u of a) {
console.log('Deleting User: ' + u.id);
await ThirdPartyApi.deleteUser({id: u.id});
}
console.log('Sleeping for 1 sec');
await delay(1000);
}
};
Upvotes: 1