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
が出力されるようにする最も簡単な方法は何ですか?コードを簡素化するために、サードパーティを使用できます。
mongoose
を使用しているようですので、サーバー側のJavaScriptについて話していることになります。その場合、 async module を見てアドバイスし、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);
});
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);
これにより、各コレクションがドロップされ、各コレクションの後に「ドロップ」が印刷され、完了時に「すべてドロップ」が印刷されます。エラーが発生すると、stderr
に表示されます。
Q promisesまたは Bluebird promisesを使用します。
WithQ:
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);
WithBluebird:
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 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);
もちろん、この種のコードをより一般的または再利用可能にする多くの方法があり、 多くの非同期プログラミングライブラリ には、この種のことを行う関数が少なくとも1つ必要です。
@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');
});
私は外部ライブラリなしでこれを行います:
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');
}
});
});
すべての答えはかなり古いです。 2013年の初めにすべてのクエリで promises が徐々にサポートされるようになったので、これが今後必要な順序でいくつかの非同期呼び出しを構築する推奨される方法になると思います。
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");
}
deferred
(別のpromise/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);