Vadim Fedorov Vadim Fedorov - 2 months ago 6
Node.js Question

JS: elegant way to wait for callbacks to finish

In my node app, I need to spawn multiple file writes and wait for them to finish before I proceed to other stuff. I've achieved that in the following way:

let counter = 0;
(some loop declaration) {
// (preparing data etc)
counter += 1;
fs.writeFile(fname, fdata, (err) => {
counter -= 1;
});
}
let waitForCallbacks = function() {
if (fcounter > 0) {
setTimeout(waitForCallbacks, 0);
}
};
waitForCallbacks();


While it works as desired, I feel that there could be some nicer idiom for that. Any suggestions?

Answer

While it works as desired, I feel that there could be some nicer idiom for that.

This is one of the things promises are designed for. Here's that code rewritten with promises (and it could go further, there are libs to promise-ify NodeJS APIs):

let operations = []
(some loop declaration) {
    // (preparing data etc)
    operations.push(new Promise((resolve, reject) => {
        fs.writeFile(fname, fdata, (err) => {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
    }));
}
Promise.all(operations).then(() => {
    // All done
});

Or consider if we have a promise-ified version of writeFile:

let operations = []
(some loop declaration) {
    // (preparing data etc)
    operations.push(writeFileWithPromise(fname, fdata));
}
Promise.all(operations).then(() => {
    // All done
});

Or if the "loop" is over an iterable that we can turn into an array and use map on:

Promise.all(
    Array.from(theThingy).map(entry => writeFileWithPromise(entry.fname, entry.fdata))
).then(() => {
    // All done
});
Comments