Вопрос по node.js, javascript, mongoose, asynchronous – Самый простой способ дождаться завершения некоторых асинхронных задач, в Javascript?

108

Я хочу удалить несколько коллекций 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');

Консоль отображает:

all dropped
dropped
dropped
dropped

Какой самый простой способ убедитьсяall dropped будет напечатан после того, как все коллекции будут удалены? Любая сторонняя программа может быть использована для упрощения кода.

Ваш Ответ

8   ответов
0

С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);
1

Если вы используете 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");
}
Error: User Rate Limit Exceededdrop()Error: User Rate Limit ExceededonDrop?
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);

Конечно, есть много способов сделать этот вид кода более общим или многократно используемым, и любой измного библиотек асинхронного программирования там должна быть хотя бы одна функция, чтобы делать подобные вещи.

Error: User Rate Limit Exceeded
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');
        }
    });                
});
125

использованиеобещания.

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

Это отбрасывает каждую коллекцию, печатая & # x201C; drop & # x201D; после каждого, а затем печатает & # x201C; все отброшено & # x201D; когда закончите. Если возникает ошибка, она отображается наstderr.


Previous answer (this pre-dates Node’s native support for Promises):

использование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);

С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);
Error: User Rate Limit Exceededfunction abc(data){Error: User Rate Limit Exceededfunction abc(err, callback){...Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededpromisifyAllError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededbluebirdjs.com/docs/api/promise.promisifyall.html
Error: User Rate Limit ExceededBluebirdError: User Rate Limit Exceededrequire('bluebird').
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');
});

ИМХО, это делает код более эффективным и разборчивым. Я взял на себя смелость удалить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');
});
90

Я вижу, вы используете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);
});
Error: User Rate Limit ExceededforEachError: User Rate Limit Exceededdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Error: User Rate Limit ExceededforEachError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededen.wikipedia.org/wiki/Callback_(computer_programming)
4

Все ответы довольно старые. С начала 2013 года Мангуст начал поддерживатьобещания постепенно для всех запросов, так что это будет рекомендуемый способ структурирования нескольких асинхронных вызовов в требуемом порядке, я думаю.

Похожие вопросы