2012-04-04 11 views
63

मैं कोड है कि जावास्क्रिप्ट में कुछ इस तरह दिखता है:मैं एसिंक्रोनस कॉलबैक फ़ंक्शंस के सेट के लिए कैसे प्रतीक्षा कर सकता हूं?

forloop { 
    //async call, returns an array to its callback 
} 

उन async कॉल किया जाता है की सब के बाद, मैं सरणियों के सब से अधिक मिनट गणना करना चाहते हैं।

मैं उन सभी के लिए कैसे इंतजार कर सकता हूं?

मेरी केवल अभी विचार बूलियन्स किया कहा जाता है की एक सरणी के लिए है, और सेट किया [i] ith कॉलबैक फ़ंक्शन में सच है, तो कहते हैं, जबकि (सभी नहीं किया जाता है) {}

संपादित करें: मुझे लगता है कि एक संभव, लेकिन बदसूरत समाधान, प्रत्येक कॉलबैक में किए गए सरणी को संपादित करना होगा, फिर एक विधि को कॉल करें यदि अन्य सभी किए गए प्रत्येक कॉलबैक से सेट किए गए हैं, इस प्रकार पूरा करने के लिए अंतिम कॉलबैक निरंतर विधि को कॉल करेगा।

अग्रिम धन्यवाद।

+1

एसिंक पर आपका मतलब है कि अजाक्स के अनुरोध को पूरा करने का इंतजार है? –

+5

नोट, 'जबकि (सभी नहीं किए गए हैं) {}' काम नहीं करेगा। जबकि आप व्यस्त-प्रतीक्षा कर रहे हैं, आपकी कोई भी कॉलबैक नहीं चल सकती है। – cHao

+0

हां। मैं एक बाहरी एपीआई को वापस आने के लिए एसिंक कॉल का इंतजार कर रहा हूं ताकि वह कॉलबैक विधियों को आग लगा दे।हाँ cHao, मुझे एहसास हुआ कि, यही कारण है कि मैं यहां मदद के लिए पूछ रहा हूँ: डी – codersarepeople

उत्तर

137

आप अपने कोड के साथ बहुत विशिष्ट नहीं हैं, इसलिए मैं एक परिदृश्य तैयार करूंगा। मान लीजिए कि आपके पास 10 AJAX कॉल हैं और आप उन 10 AJAX कॉल से परिणामों को जमा करना चाहते हैं और फिर जब वे पूरा हो गए हैं तो आप कुछ करना चाहते हैं।

मैनुअल काउंटर

var ajaxCallsRemaining = 10; 
var returnedData = []; 

for (var i = 0; i < 10; i++) { 
    doAjax(whatever, function(response) { 
     // success handler from the ajax call 

     // save response 
     returnedData.push(response); 

     // see if we're done with the last ajax call 
     --ajaxCallsRemaining; 
     if (ajaxCallsRemaining <= 0) { 
      // all data is here now 
      // look through the returnedData and do whatever processing 
      // you want on it right here 
     } 
    }); 
} 

नोट:: त्रुटि हैंडलिंग यहां महत्वपूर्ण है (इसलिए नहीं कि पता चला आप एक सरणी में डेटा जमा और जब पिछले एक समाप्त हो गया है का ट्रैक रखने के द्वारा इस तरह यह कर सकते हैं यह विशिष्ट है कि आप अपनी AJAX कॉल कैसे बना रहे हैं)। आप इस बारे में सोचना चाहेंगे कि आप इस मामले को कैसे संभालने जा रहे हैं जब एक AJAX कॉल कभी पूरा नहीं होता है, या तो त्रुटि के साथ या लंबे समय तक लंबे समय तक या बाहर निकल जाता है।


jQuery वादे

2014 में मेरा उत्तर को जोड़ना इन दिनों, वादे अक्सर के बाद से jQuery के $.ajax() पहले से ही एक वादा वापस आती है और $.when() तुम्हें पता है जब एक दूँगी इस प्रकार की समस्या हल करने के लिए उपयोग किया जाता है वादे के समूह के सभी हल कर रहे हैं और आप के लिए वापसी परिणाम एकत्रित करेगा:

var promises = []; 
for (var i = 0; i < 10; i++) { 
    promises.push($.ajax(...)); 
} 
$.when.apply($, promises).then(function() { 
    // returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0] 
    // you can process it here 
}, function() { 
    // error occurred 
}); 

ES6 स्टैंडर्ड वादे

As specified in kba's answer: यदि आप मूल अंतर्निहित वादों (आधुनिक ब्राउज़र या Node.js या babeljs transpile का उपयोग कर या एक वादा polyfill का प्रयोग करके) के साथ एक वातावरण है, तो आप ES6 द्वारा निर्दिष्ट वादों का उपयोग कर सकते हैं। ब्राउज़र समर्थन के लिए this table देखें। IE को छोड़कर, वादे को सभी मौजूदा ब्राउज़रों में बहुत अधिक समर्थित किया जाता है।

doAjax() एक वादा देता है, तो आप ऐसा कर सकते हैं:

var promises = []; 
for (var i = 0; i < 10; i++) { 
    promises.push(doAjax(...)); 
} 
Promise.all(promises).then(function() { 
    // returned data is in arguments[0], arguments[1], ... arguments[n] 
    // you can process it here 
}, function(err) { 
    // error occurred 
}); 

आप एक है कि एक वादा रिटर्न में एक गैर वादा async आपरेशन करने की जरूरत है, तो आप "promisify" यह कर सकते हैं

function doAjax(...) { 
    return new Promise(function(resolve, reject) { 
     someAsyncOperation(..., function(err, result) { 
      if (err) return reject(err); 
      resolve(result); 
     }); 
    }); 
} 

और, फिर ऊपर पैटर्न का उपयोग:

var promises = []; 
for (var i = 0; i < 10; i++) { 
    promises.push(doAjax(...)); 
} 
Promise.all(promises).then(function() { 
    // returned data is in arguments[0], arguments[1], ... arguments[n] 
    // you can process it here 
}, function(err) { 
    // error occurred 
}); 
0 इस तरह

Bluebird वादे

आप इस आसान बनाने के लिए, Bluebird promise library के रूप में एक और अधिक सुविधा अमीर पुस्तकालय ऐसे का उपयोग करते हैं तो यह में बनाया कुछ अतिरिक्त कार्य करता है:

var doAjax = Promise.promisify(someAsync); 
var someData = [...] 
Promise.map(someData, doAjax).then(function(results) { 
    // all ajax results here 
}, function(err) { 
    // some error here 
}); 
+1

jQuery समाधान मेरे लिए बहुत अच्छा काम करता है! – larrydahooster

+3

@kba - मैं इस जवाब को पुराना नहीं कहूंगा क्योंकि सभी तकनीकें अभी भी लागू हैं, खासकर यदि आप पहले ही अजाक्स के लिए jQuery का उपयोग कर रहे हैं। लेकिन, मैंने देशी वादों को शामिल करने के कई तरीकों से इसे अद्यतन किया है। – jfriend00

+0

थीसिस दिनों में एक बहुत साफ समाधान है जिसे jquery की भी आवश्यकता नहीं है। मैं इसे FetchAPI और वादे के साथ कर रहा हूं –

9

आप when विधि के साथ jQuery की Deferred ऑब्जेक्ट का उपयोग कर सकते हैं।

deferredArray = []; 
forloop { 
    deferred = new $.Deferred(); 
    ajaxCall(function() { 
     deferred.resolve(); 
    } 
    deferredArray.push(deferred); 
} 

$.when(deferredArray, function() { 
    //this code is called after all the ajax calls are done 
}); 
+7

प्रश्न 'jQuery' के लिए टैग नहीं किया गया था जिसका आमतौर पर ओपी को jQuery उत्तर नहीं चाहिए था। – jfriend00

+8

@ jfriend00 मैं पहिया को फिर से शुरू नहीं करना चाहता था जब यह पहले से ही jQuery – Paul

+4

@ पॉल में बनाया गया था, तो फिर कुछ सरल (स्थगित) – Raynos

7

आप का अनुकरण कर सकते हैं यह इस तरह है:

countDownLatch = { 
    count: 0, 
    check: function() { 
     this.count--; 
     if (this.count == 0) this.calculate(); 
    }, 
    calculate: function() {...} 
    }; 

तो प्रत्येक async कॉल डी ओ इ एस यह:

countDownLatch.count++; 

जबकि प्रत्येक asynch विधि के अंत में वापस कॉल में आप इस पंक्ति जोड़ें:

countDownLatch.check(); 

दूसरे शब्दों में, यदि आप एक गिनती डाउन-कुंडी कार्यक्षमता का अनुकरण।

+0

सभी उपयोग मामलों में से 99% में वादा करने का तरीका है लेकिन मुझे यह जवाब पसंद है क्योंकि यह उन स्थितियों में Async कोड को प्रबंधित करने के लिए एक विधि को दिखाता है जहां एक वादा पॉलीफ़िल बड़ा होता है तो जेएस इसका उपयोग करता है! – Sukima

1

उपयोग after

after.map(array, function (value, done) { 
    // do something async 
    setTimeout(function() { 
     // do something with the value 
     done(null, value * 2) 
    }, 10) 
}, function (err, mappedArray) { 
    // all done, continue here 
    console.log(mappedArray) 
}) 
9

2015 से में जाँच हो रही है की तरह एक नियंत्रण प्रवाह पुस्तकालय: अब हम most recent browser में native promises (एज 12, फ़ायरफ़ॉक्स 40, क्रोम 43, सफारी 8, ओपेरा 32 है और Android ब्राउज़र 4.4.4 और आईओएस सफारी 8.4, लेकिन इंटरनेट एक्सप्लोरर, ओपेरा मिनी और एंड्रॉइड के पुराने संस्करण नहीं)।

हम 10 async कार्रवाई करने के लिए और जब वे सब समाप्त कर लिया है, हम देशी Promise.all उपयोग कर सकते हैं, किसी भी बाहरी पुस्तकालयों के बिना सूचित किया जाए चाहते हैं:

function asyncAction(i) { 
    return new Promise(function(resolve, reject) { 
     var result = calculateResult(); 
     if (result.hasError()) { 
      return reject(result.error); 
     } 
     return resolve(result); 
    }); 
} 

var promises = []; 
for (var i=0; i < 10; i++) { 
    promises.push(asyncAction(i)); 
} 

Promise.all(promises).then(function AcceptHandler(results) { 
    handleResults(results), 
}, function ErrorHandler(error) { 
    handleError(error); 
}); 
+1

'Promises.all()' 'Promise.all()' होना चाहिए। – jfriend00

+1

आपके उत्तर को [कौन से ब्राउज़र्स] (http://caniuse.com/#feat=promises) का संदर्भ लेने की आवश्यकता है, आप 'Promise.all()' का उपयोग कर सकते हैं जिसमें IE के वर्तमान संस्करण शामिल नहीं हैं। – jfriend00

2

यह मेरी राय में सबसे साफ रास्ता है ।

Promise.all

FetchAPI

(किसी कारण से Array.map मेरे लिए तो फिर कार्यों के अंदर काम नहीं करता। लेकिन अगर आप एक .forEach और [] .concat() या कुछ इसी तरह का उपयोग कर सकते हैं)

Promise.all([ 
    fetch('/user/4'), 
    fetch('/user/5'), 
    fetch('/user/6'), 
    fetch('/user/7'), 
    fetch('/user/8') 
]).then(responses => { 
    return responses.map(response => {response.json()}) 
}).then((values) => { 
    console.log(values); 
}) 
+0

मुझे लगता है कि इसे 'वापसी प्रतिक्रियाएं। मैप (प्रतिक्रिया => {वापसी प्रतिक्रिया.जेसन();})', या 'वापसी प्रतिक्रियाएं। मैप (प्रतिक्रिया => प्रतिक्रिया.जेसन())'। –

संबंधित मुद्दे