Trying to block-sleep in some js/node code using setTimeout

javascript node.js

60 观看

1回复

46663 作者的声誉

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.
作者: Pure.Krome 的来源 发布者: 2017 年 9 月 15 日

回应 1


1

177209 作者的声誉

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);
    }
};
作者: Ry- 发布者: 2017 年 9 月 15 日
32x32