最简单的方法来等待一些asynchronous任务完成,在Javascript中?

我想删除一些MongoDB集合,但这是一个asynchronous任务。 代码将是:

var mongoose = require('mongoose'); mongoose.connect('mongo://localhost/xxx'); var conn = mongoose.connection; ['aaa','bbb','ccc'].forEach(function(name){ conn.collection(name).drop(function(err) { console.log('dropped'); }); }); console.log('all dropped'); 

控制台显示:

 all dropped dropped dropped dropped 

什么是最简单的方法来确保all dropped将被打印所有集合已被删除后? 任何第三方都可以用来简化代码。

我看到你正在使用mongoose所以你在谈论服务器端的JavaScript。 在这种情况下,我build议查看asynchronous模块,并使用async.parallel(...) 。 你会发现这个模块真的很有帮助 – 它的开发是为了解决你正在努力的问题。 你的代码可能看起来像这样

 var async = require('async'); var calls = []; ['aaa','bbb','ccc'].forEach(function(name){ calls.push(function(callback) { conn.collection(name).drop(function(err) { if (err) return callback(err); console.log('dropped'); callback(null, name); }); } )}); async.parallel(calls, function(err, result) { /* this code will run after all calls finished the job or when any of the calls passes an error */ if (err) return console.log(err); console.log(result); }); 

使用承诺 。

 var mongoose = require('mongoose'); mongoose.connect('your MongoDB connection string'); var conn = mongoose.connection; var promises = ['aaa', 'bbb', 'ccc'].map(function(name) { return new Promise(function(resolve, reject) { var collection = conn.collection(name); collection.drop(function(err) { if (err) { return reject(err); } console.log('dropped ' + name); resolve(); }); }); }); Promise.all(promises) .then(function() { console.log('all dropped)'); }) .catch(console.error); 

这会使每个集合都下降,每个集合打印后“下降”,然后在完成时打印“全部下降”。 如果发生错误,则显示为stderr


以前的答案(这是Node前期对Promise的本地支持):

使用Q承诺或蓝鸟承诺。

Q

 var Q = require('q'); var mongoose = require('mongoose'); mongoose.connect('your MongoDB connection string'); var conn = mongoose.connection; var promises = ['aaa','bbb','ccc'].map(function(name){ var collection = conn.collection(name); return Q.ninvoke(collection, 'drop') .then(function() { console.log('dropped ' + name); }); }); Q.all(promises) .then(function() { console.log('all dropped'); }) .fail(console.error); 

蓝鸟

 var Promise = require('bluebird'); var mongoose = Promise.promisifyAll(require('mongoose')); mongoose.connect('your MongoDB connection string'); var conn = mongoose.connection; var promises = ['aaa', 'bbb', 'ccc'].map(function(name) { return conn.collection(name).dropAsync().then(function() { console.log('dropped ' + name); }); }); Promise.all(promises) .then(function() { console.log('all dropped'); }) .error(console.error); 

做到这一点的方法是传递任务更新共享计数器的callback。 当共享计数器达到零时,您知道所有任务都已完成,因此您可以继续正常stream程。

 var ntasks_left_to_go = 4; var callback = function(){ ntasks_left_to_go -= 1; if(ntasks_left_to_go <= 0){ console.log('All tasks have completed. Do your stuff'); } } task1(callback); task2(callback); task3(callback); task4(callback); 

当然,有很多方法可以使这种代码更通用或者可重用,而且那里的许多asynchronous编程库至less应该有一个这样的function。

扩展@freakish的答案,asynchronous还提供了一种方法,这似乎特别适合你的情况:

 var async = require('async'); async.each(['aaa','bbb','ccc'], function(name, callback) { conn.collection(name).drop( callback ); }, function(err) { if( err ) { return console.log(err); } console.log('all dropped'); }); 

恕我直言,这使得代码更有效率和更清晰。 我冒昧地删除了console.log('dropped') – 如果你需要的话,用这个代替:

 var async = require('async'); async.each(['aaa','bbb','ccc'], function(name, callback) { // if you really want the console.log( 'dropped' ), // replace the 'callback' here with an anonymous function conn.collection(name).drop( function(err) { if( err ) { return callback(err); } console.log('dropped'); callback() }); }, function(err) { if( err ) { return console.log(err); } console.log('all dropped'); }); 

我这样做没有外部的库:

 var yourArray = ['aaa','bbb','ccc']; var counter = []; yourArray.forEach(function(name){ conn.collection(name).drop(function(err) { counter.push(true); console.log('dropped'); if(counter.length === yourArray.length){ console.log('all dropped'); } }); }); 

所有的答案都很古老。 从2013年开始,Mongoose开始逐渐支持对所有查询的承诺 ,所以这将是推荐的方式来构build几个asynchronous调用按我所要求的顺序进行。

如果你正在使用Babel或者这样的transpilers并且使用asynchronous/等待,你可以这样做:

 function onDrop() { console.log("dropped"); } async function dropAll( collections ) { const drops = collections.map(col => conn.collection(col).drop(onDrop) ); await drops; console.log("all dropped"); } 

随着deferred (另一个承诺/延期实施),你可以做:

 // Setup 'pdrop', promise version of 'drop' method var deferred = require('deferred'); mongoose.Collection.prototype.pdrop = deferred.promisify(mongoose.Collection.prototype.drop); // Drop collections: deferred.map(['aaa','bbb','ccc'], function(name){ return conn.collection(name).pdrop()(function () { console.log("dropped"); }); }).end(function () { console.log("all dropped"); }, null);