JS:优雅的方式来等待callback完成

在我的节点应用程序中,我需要产生多个文件写入,并等待他们完成之前,我继续其他的东西。 我通过以下方式实现了这一点:

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(); 

虽然它按照我们所希望的那样工作,但我觉得可能有一些更好的习惯用法。 有什么build议么?

虽然它按照我们所希望的那样工作,但我觉得可能有一些更好的习惯用法。

这是承诺的目的之一。 这是用承诺重写的代码(它可以进一步,有许多承诺 – 如果NodeJS的API):

 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 }); 

或者考虑一下,如果我们有一个承诺的writeFile版本:

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

或者,如果“循环”遍历一个迭代器,我们可以把它变成一个数组,并使用map

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

承诺是一种方式。 但是,如果你不喜欢它们,你可以使用一个非常有名的叫async的库。

这就是你可以在你的情况下做什么。 以下是使用并行处理的基本方式:

 async.parallel([ function(done) { fs.writeFile(fname1, fdata1, (err) => { done(err, customResults1); }); }, function(done) { fs.writeFile(fname2, fdata2, (err) => { done(err, customResults2); }); } ], // The callback when every function above is done function(err, results) { // `results` contains a collection of what you've passed // on the `done` callbacks above }); 

为了更具体到你的用例,它看起来像:

 async.parallel( ['file1', 'file2'].map(function(fname) { return function(done) { fs.writeFile(fname, fdata, (err) => { done(err, customResults); }); }; }), // The callback when every function above is done function(err, results) { // `results` contains a collection of what you've passed // on the `done` callbacks above } ); 

如果你想要一个一个地运行任务,那么你可以使用async.series 。 如果您希望函数将结果传递给下一个任务,则可以使用async.waterfall 。 当然,还有其他的function可以使用,但是我提到的是一些非常常见的function。

使用asynchronous:

 async.map([['name1', 'data1'], ['name2', 'data2'], ['name3', 'data3']], function (item, cb) { fs.writeFile(item[0], item[1], (err, res) => { callback(err, res); }); }, function(err, results) { // results is now an array of results }); 

我已经尝试了Promises,并且我不完全相信使用它们做这样的事情有很多好处:

  let counter = 0; (some loop declaration) { // (preparing data etc) counter += 1; fs.writeFile(fname, fdata, (err) => { counter -= 1; if ( counter==0 ) done() }); } function done(){ // that's it } 

非常类似于您的初始代码,除了不使用setTimeout(),我检查每个操作完成时计数器的值。

国际海事组织,这是一样有效的,也许更容易阅读。

或者,如果你不喜欢有一个单独的function完成…

  let counter = 0; (some loop declaration) { // (preparing data etc) counter += 1; fs.writeFile(fname, fdata, (err) => { counter -= 1; if ( counter==0 ) { // that's it, finish up } }); }