Javascript 在Javascript中等待一些异步任务完成的最简单方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10551499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Simplest way to wait some asynchronous tasks complete, in Javascript?
提问by Freewind
I want to drop some mongodb collections, but that's an asynchronous task. The code will be:
我想删除一些 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) {
console.log('dropped');
});
});
console.log('all dropped');
The console displays:
控制台显示:
all dropped
dropped
dropped
dropped
What is the simplest way to make sure all dropped
will be printed after all collections has been dropped? Any 3rd-party can be used to simplify the code.
确保all dropped
在删除所有集合后打印的最简单方法是什么?任何 3rd-party 都可以用来简化代码。
采纳答案by freakish
I see you are using mongoose
so you are talking about server-side JavaScript. In that case I advice looking at async moduleand use async.parallel(...)
. You will find this module really helpful - it was developed to solve the problem you are struggling with. Your code may look like this
我看到您正在使用,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);
});
回答by Nate
Use Promises.
使用承诺。
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);
This drops each collection, printing “dropped” after each one, and then prints “all dropped” when complete. If an error occurs, it is displayed to stderr
.
这会丢弃每个集合,在每个集合之后打印“dropped”,然后在完成时打印“all drop”。如果发生错误,则显示为stderr
。
Previous answer (this pre-dates Node's native support for Promises):
上一个答案(这早于 Node 对 Promise 的原生支持):
Use Qpromises or Bluebirdpromises.
With 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);
With Bluebird:
与蓝鸟:
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);
回答by hugomg
The way to do it is to pass the tasks a callback that updates a shared counter. When the shared counter reaches zero you know that all tasks have finished so you can continue with your normal flow.
这样做的方法是向任务传递一个更新共享计数器的回调。当共享计数器达到零时,您就知道所有任务都已完成,因此您可以继续正常流程。
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);
Of course, there are many ways to make this kind of code more generic or reusable and any of the many async programing librariesout there should have at least one function to do this kind of thing.
当然,有很多方法可以使这种代码更通用或可重用,并且许多异步编程库中的任何一个都应该至少有一个函数来做这种事情。
回答by Erwin Wessels
Expanding upon @freakish answer, async also offers a each method, which seems especially suited for your case:
扩展@freakish 答案,async 还提供了 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');
});
IMHO, this makes the code both more efficient and more legible. I've taken the liberty of removing the console.log('dropped')
- if you want it, use this instead:
恕我直言,这使代码更高效,更清晰。我冒昧地删除了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');
});
回答by user435943
I do this without external libaries:
我在没有外部库的情况下这样做:
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');
}
});
});
回答by Capaj
All answers are quite old. Since the beginning of 2013 Mongoose started to support promisesgradually for all queries, so that would be the recommended way of structuring several async calls in the required order going forward I guess.
所有的答案都很旧。自 2013 年初以来,Mongoose 开始逐渐支持所有查询的承诺,因此我猜这将是按所需顺序构建多个异步调用的推荐方式。
回答by ganaraj
If you are using Babel or such transpilers and using async/await you could do :
如果您使用 Babel 或此类转译器并使用 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");
}
回答by Mariusz Nowak
With deferred
(another promise/deferred implementation) you can do:
使用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);