wake-up-neo.com

Der einfachste Weg, um einige asynchrone Aufgaben in Javascript zu erledigen?

Ich möchte einige Mongodb-Sammlungen löschen, aber das ist eine asynchrone Aufgabe. Der Code wird sein:

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

Die Konsole zeigt Folgendes an:

all dropped
dropped
dropped
dropped

Was ist der einfachste Weg, um sicherzustellen, dass all dropped wird gedruckt, nachdem alle Sammlungen gelöscht wurden? Jeder Drittanbieter kann zur Vereinfachung des Codes verwendet werden.

110
Freewind

Wie ich sehe, verwenden Sie mongoose, also sprechen Sie über serverseitiges JavaScript. In diesem Fall rate ich zu async module und benutze async.parallel(...). Sie werden dieses Modul als sehr hilfreich empfinden - es wurde entwickelt, um das Problem zu lösen, mit dem Sie zu kämpfen haben. Ihr Code könnte so aussehen

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);
});
91
freakish

Verwenden Sie Versprechen .

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

Dies löscht jede Sammlung, druckt nach jeder Sammlung "fallen gelassen" und druckt dann "alle fallen gelassen", wenn der Vorgang abgeschlossen ist. Wenn ein Fehler auftritt, wird er stderr angezeigt.


Vorherige Antwort (dies datiert vor der nativen Unterstützung von Node für Promises):

Verwenden Sie Q Versprechen oder Bluebird Versprechen.

Mit [~ # ~] 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);

Mit 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);
125
Nate

Der Weg, dies zu tun, besteht darin, den Aufgaben einen Rückruf zu übergeben, der einen gemeinsam genutzten Zähler aktualisiert. Wenn der gemeinsame Zähler Null erreicht, wissen Sie, dass alle Aufgaben abgeschlossen sind, sodass Sie mit Ihrem normalen Ablauf fortfahren können.

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

Natürlich gibt es viele Möglichkeiten, um diese Art von Code allgemeiner oder wiederverwendbarer zu machen, und jede der viele asynchrone Programmierbibliotheken da draußen sollte mindestens eine Funktion haben, um diese Art von Dingen auszuführen.

21
hugomg

Neben der @freakish-Antwort bietet async auch jede Methode an, die für Ihren Fall besonders geeignet zu sein scheint:

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, das macht den Code sowohl effizienter als auch lesbarer. Ich habe mir erlaubt, die Funktion console.log('dropped') zu entfernen. Wenn Sie dies wünschen, verwenden Sie stattdessen diese Option:

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');
});
7
Erwin Wessels

Ich mache das ohne externe Bibliotheken:

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');
        }
    });                
});
5
user435943

Alle Antworten sind ziemlich alt. Seit Anfang 2013 unterstützt Mongoose nach und nach Versprechen für alle Abfragen. Dies ist also die empfohlene Methode, um mehrere asynchrone Aufrufe in der erforderlichen Reihenfolge zu strukturieren.

4
Capaj

Wenn Sie Babel oder solche Transpiler verwenden und async/await verwenden, können Sie Folgendes tun:

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");
}
1
ganaraj

Mit deferred (ein weiteres Versprechen/eine verzögerte Implementierung) können Sie Folgendes tun:

// 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);
0
Mariusz Nowak