जावास्क्रिप्ट में कुछ अतुल्यकालिक कार्यों को पूरा करने का सबसे सरल तरीका?


112

मैं कुछ मोंगोडब संग्रह छोड़ना चाहता हूं, लेकिन यह एक अतुल्यकालिक कार्य है। कोड होगा:

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सभी संग्रह को गिरा दिए जाने के बाद मुद्रित किया जाएगा? किसी भी 3-पार्टी का उपयोग कोड को सरल बनाने के लिए किया जा सकता है।

जवाबों:


92

मैं देख रहा हूं कि आप mongooseसर्वर-साइड जावास्क्रिप्ट के बारे में बात कर रहे हैं। उस मामले में मैं async मॉड्यूल और उपयोग को देखने की सलाह देता हूं 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);
});

इस के साथ ... forEach विधि async होती है। इसलिए यदि ऑब्जेक्ट सूची यहां विस्तृत 3 से अधिक थी, तो क्या यह मामला नहीं हो सकता है कि जब async.parallel (कॉल, फ़ंक्शन (इरेट, परिणाम) का मूल्यांकन किया जाता है तो मूल सूची में सभी फ़ंक्शन शामिल नहीं होते हैं?
मार्टिन बीबी

5
@MartinBeeby forEachसमकालिक है। यहाँ एक नज़र रखें: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…forEach नीचे सबसे ऊपर कार्यान्वयन है । कॉलबैक के साथ सब कुछ अतुल्यकालिक नहीं है।
अजीब

2
रिकॉर्ड के लिए, async ब्राउज़र में भी उपयोग किया जा सकता है।
इरविन वेसल्स

@MartinBeeby एक कॉलबैक के साथ सब कुछ अतुल्यकालिक है, समस्या यह है कि forEach को "कॉलबैक" पारित नहीं किया जा रहा है, लेकिन सिर्फ एक नियमित फ़ंक्शन (जो मोज़िला द्वारा शब्दावली का गलत उपयोग है)। एक कार्यात्मक प्रोग्रामिंग भाषा में, आप कभी भी पास किए गए फ़ंक्शन को "कॉलबैक" नहीं कहेंगे

3
@ ghert85 नहीं, शब्दावली में कुछ भी गलत नहीं है। कॉलबैक बस किसी भी निष्पादन योग्य कोड है जिसे अन्य कोड के तर्क के रूप में पारित किया जाता है और कुछ बिंदु पर निष्पादित होने की उम्मीद की जाती है। वह मानक परिभाषा है। और इसे सिंक्रोनस या एसिंक्रोनसली कहा जा सकता है। : इस देखें en.wikipedia.org/wiki/Callback_(computer_programming)
अजीब

128

वादे का प्रयोग करें ।

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


पिछला उत्तर (यह प्रॉमिस के लिए नोड का मूल समर्थन पूर्व-दिनांक):

क्यू वादों या ब्लूबर्ड वादों का उपयोग करें ।

क्यू के साथ :

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

ब्लूबर्ड के साथ :

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

1
वादे जाने का रास्ता हैं। ब्लूबर्ड एक और वादा पुस्तकालय है जो प्रदर्शन-महत्वपूर्ण कोड में होने पर अच्छा काम करेगा। यह एक ड्रॉप-इन प्रतिस्थापन होना चाहिए। बस उपयोग करें require('bluebird')
वीयन

मैंने एक ब्लूबर्ड उदाहरण जोड़ा है। यह ब्लूबर्ड का उपयोग करने का सबसे अच्छा तरीका है क्योंकि यह promisifyAllसुविधा का उपयोग करना है।
नैट

किसी भी विचार कैसे promisifyAll काम करता है..मैं डॉक्स पढ़ा है, लेकिन मैं यह नहीं है कि यह कैसे है कि यह ऐसे कार्यों को संभालता है जो मापदंडों की तरह नहीं है function abc(data){, क्योंकि यह function abc(err, callback){...मूल रूप से ऐसा नहीं है, मुझे नहीं लगता कि सभी कार्य पहले परम के रूप में त्रुटि लेते हैं और 2 डी परम के रूप में कॉलबैक करते हैं।
मुहम्मद उमेर

@MuhammadUmer का विस्तार बहुत सारे ब्लूबर्डjs.com/docs/api/promise.promisifyall.html
Nate

जब से MongoDB ड्राइवर वादों का समर्थन करता है तब से कुछ समय हो गया है। क्या आप इसका लाभ उठाने के लिए अपना उदाहरण अपडेट कर सकते हैं? .map(function(name) { return conn.collection(name).drop() })
djanowski

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

बेशक, इस तरह के कोड को अधिक जेनेरिक या पुन: प्रयोज्य बनाने के कई तरीके हैं और कई असिंच प्रोग्रामिंग लाइब्रेरी में से कोई भी इस तरह का काम करने के लिए कम से कम एक फ़ंक्शन होना चाहिए।


यह लागू करना सबसे आसान नहीं हो सकता है, लेकिन मुझे वास्तव में एक जवाब देखना पसंद है जिसमें बाहरी मॉड्यूल की आवश्यकता नहीं है। धन्यवाद!
counterbeing

8

@ जवाब में विस्तार करते हुए, 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');
});

IMHO, यह कोड को अधिक कुशल और अधिक सुपाठ्य बनाता है। मैंने हटाने की स्वतंत्रता ली है 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');
});

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

4

सभी उत्तर काफी पुराने हैं। 2013 की शुरुआत के बाद से मोंगोज़ ने सभी प्रश्नों के लिए धीरे-धीरे वादों का समर्थन करना शुरू कर दिया , इसलिए मुझे लगता है कि आगे बढ़ने के लिए आवश्यक आदेश में कई async कॉल को संरचित करने का अनुशंसित तरीका होगा।


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

0

यदि आप बैबल या ऐसे ट्रांसपाइलर का उपयोग कर रहे हैं और एसिंक्स / वेट का उपयोग कर रहे हैं, तो आप कर सकते हैं:

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

आप एक कॉलबैक पास नहीं कर सकते हैं drop()और एक वादा वापस करने की उम्मीद कर सकते हैं। क्या आप कृपया इस उदाहरण को ठीक कर सकते हैं और हटा सकते हैं onDrop?
djanowski
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.