用Javascript等待异步任务完成的最简单方法?
我想删除一些mongodb集合,但这是一项异步任务。守则如下:用Javascript等待异步任务完成的最简单方法?,javascript,node.js,asynchronous,mongoose,synchronous,Javascript,Node.js,Asynchronous,Mongoose,Synchronous,我想删除一些mongodb集合,但这是一项异步任务。守则如下: 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) { conso
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
最简单的方法是什么,以确保在删除所有集合后打印所有删除的
?任何第三方都可以用来简化代码。我看到您使用的是mongoose
,所以您说的是服务器端JavaScript。在这种情况下,我建议查看并使用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 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);
var ntasks_left_to_go=4;
var callback=function(){
ntasks_left_to_go-=1;
如果(ntasks_left__go使用
这会删除每个集合,在每个集合之后打印“已删除”,然后在完成后打印“全部已删除”。如果出现错误,则会显示到stderr
上一个答案(此日期早于节点对承诺的本机支持):
使用承诺或承诺
使用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);
与蓝鸟一起:
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);
使用延期
(另一个承诺/延期实施),您可以:
// 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);
async扩展了@freakish answer,还提供了一个each方法,它似乎特别适合您的情况:
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('droped')
——如果您需要它,请改用它:
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');
});
所有答案都非常陈旧。自2013年初以来,Mongoose开始逐渐支持所有查询,因此我想这将是按照所需顺序构建多个异步调用的推荐方法。我这样做时没有外部库:
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');
}
});
});
如果您使用Babel或类似的Transpiler并使用async/await,您可以执行以下操作:
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");
}
因此,如果对象列表比这里详细介绍的3长,那么当async.parallel(调用、函数(err、result)时is evaluated调用尚未包含原始列表中的所有函数?@MartinBeebyforEach
是同步的。请看这里:底部有forEach
的实现。并不是所有回调函数都是异步的。作为记录,async也可以在浏览器中使用。@MartinBeeby everything with a callback是异步的,问题是forEach没有被传递一个“回调”,而只是一个常规函数(这是Mozilla对术语的错误使用)。在函数式编程语言中,您永远不会将传递的函数称为“回调”@ghert85不,这个术语没有错。回调就是任何作为参数传递给其他代码的可执行代码,并期望在某个时刻执行。这是标准定义。它可以同步或异步调用。请看:这可能不是最容易实现的,但我真的很喜欢seeing一个不需要外部模块的答案。谢谢!承诺是一条路。如果这是在性能关键代码中,另一个承诺库将很好地工作。它应该是一个替代品。只需使用require('bluebird'))
。我添加了一个Bluebird示例。这有点不同,因为使用Bluebird的最佳方法是使用promisifyAll
功能。知道promisifyAll是如何工作的吗?我读过文档,但我不明白它是如何处理没有参数的函数的,比如函数abc(数据){
,因为它不像函数abc(err,callback){…
基本上我不认为所有函数都把error作为第一个参数,把callback作为第二个参数param@MuhammadUmer很多细节,MongoDB驱动程序也支持promises已经有一段时间了。您能更新您的示例以利用这一点吗?.map(函数(名称)){return conn.collection(name.drop()})
您不能将回调传递给drop()
并期望返回承诺。您能否修复此示例并删除onDrop
?