在Javascript中,等待一些异步任务完成的最简单方法是什么?

Fre*_*ind 112 javascript asynchronous synchronous mongoose node.js

我想删除一些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');
Run Code Online (Sandbox Code Playgroud)

控制台显示:

all dropped
dropped
dropped
dropped
Run Code Online (Sandbox Code Playgroud)

all dropped在删除所有集合后,最简单的方法是打印什么?任何第三方都可用于简化代码.

Nat*_*ate 126

使用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);
Run Code Online (Sandbox Code Playgroud)

这会丢弃每个集合,在每个集合之后打印"丢弃",然后在完成时打印"全部丢弃".如果发生错误,则显示错误stderr.


以前的答案(这是Node对Promises的本机支持之前的事先):

使用Q promises或Bluebird承诺.

:

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);
Run Code Online (Sandbox Code Playgroud)

使用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);
Run Code Online (Sandbox Code Playgroud)


fre*_*ish 91

我看到你正在使用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);
});
Run Code Online (Sandbox Code Playgroud)

  • @MartinBeeby`forEach`是同步的.看看这里:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach底部有`forEach`的实现.并非所有回调都是异步的. (5认同)
  • @ ghert85不,这个术语没什么问题.回调只是作为参数传递给其他代码的任何可执行代码,并且预计会在某个时刻执行.这是标准定义.它可以同步或异步调用.见:https://en.wikipedia.org/wiki/Callback_ (computer_programming) (3认同)
  • 啊,谢谢@freakish总是假设它会异步. (2认同)
  • 为了记录,异步也可以在浏览器中使用. (2认同)

hug*_*omg 21

执行此操作的方法是将任务传递给更新共享计数器的回调.当共享计数器达到零时,您知道所有任务都已完成,因此您可以继续正常流程.

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);
Run Code Online (Sandbox Code Playgroud)

当然,有很多方法可以使这种代码更通用或可重用,并且那里的任何异步编程库都应该至少有一个函数来完成这种事情.


Erw*_*els 7

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

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');
});
Run Code Online (Sandbox Code Playgroud)

恕我直言,这使代码更高效,更清晰.我冒昧地删除了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');
});
Run Code Online (Sandbox Code Playgroud)


use*_*943 5

我这样做没有外部图书馆:

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');
        }
    });                
});
Run Code Online (Sandbox Code Playgroud)