$ .When.apply ($, someArray) क्या करता है?


110

मैं Deferreds और वादे के बारे में पढ़ रहा हूँ और भर में आ रहा हूँ $.when.apply($, someArray)। मैं थोड़ा स्पष्ट नहीं हूँ कि यह वास्तव में क्या करता है, एक स्पष्टीकरण की तलाश में है कि एक पंक्ति बिल्कुल काम करती है (संपूर्ण कोड स्निपेट नहीं)। यहाँ कुछ संदर्भ है:

var data = [1,2,3,4]; // the ids coming back from serviceA
var processItemsDeferred = [];

for(var i = 0; i < data.length; i++){
  processItemsDeferred.push(processItem(data[i]));
}

$.when.apply($, processItemsDeferred).then(everythingDone); 

function processItem(data) {
  var dfd = $.Deferred();
  console.log('called processItem');

  //in the real world, this would probably make an AJAX call.
  setTimeout(function() { dfd.resolve() }, 2000);    

  return dfd.promise();
}

function everythingDone(){
  console.log('processed all items');
}

1
.done().thenइस मामले में इस्तेमाल किया जा सकता है , सिर्फ FYI करें
केविन बी

2
fwiw, अंडरस्कोर करने के लिए एक डिफर्ड पोर्ट है जो एक सरणी को _.whenपास करने की अनुमति देता है ताकि आपको उपयोग करने की आवश्यकता न होapply
Eevee

इसके बारे में और जानें .apply: developer.mozilla.org/en-US/docs/JavaScript/Reference/…
फेलिक्स क्लिंग


1
ओपी ने अपने पहले वाक्य में जिस लेख को संदर्भित किया है, वह स्थान बदल गया है - अब यह है: flaviocopes.com/blog/deferreds-and-promises-in-javascript
ग्लूकोन

जवाबों:


161

.applyएक फ़ंक्शन को तर्कों के साथ कॉल करने के लिए उपयोग किया जाता है। यह सरणी में प्रत्येक तत्व को लेता है, और प्रत्येक को फ़ंक्शन के पैरामीटर के रूप में उपयोग करता है। किसी फ़ंक्शन के अंदर .applyसंदर्भ ( this) भी बदल सकते हैं ।

तो, चलो लेते हैं $.when। यह कहने के लिए उपयोग किया जाता है "जब ये सभी वादे हल हो जाते हैं ... कुछ करते हैं"। यह एक अनंत (चर) मापदंडों की संख्या लेता है।

आपके मामले में, आपके पास वादों की एक सरणी है; आप नहीं जानते कि आप कितने मापदंडों से गुजर रहे हैं $.when। सरणी को पास करने से $.whenकाम नहीं चल सकता, क्योंकि यह उम्मीद करता है कि इसके पैरामीटर वादे होंगे, सरणी नहीं।

वह जहां .applyआता है। यह सरणी लेता है, और $.whenप्रत्येक तत्व के साथ एक पैरामीटर के रूप में कॉल करता है (और यह सुनिश्चित करता है कि / के thisलिए सेट है ), तो यह सब काम करता है :-)jQuery$


3
जब कई वादे $। विधि के लिए पारित किए जाते हैं। वे किस क्रम में अमल करेंगे? एक के बाद एक या समानांतर में?
दर्शन

21
@ दर्शन: आप "वादे" नहीं चलाते। आप उनके निराकरण की प्रतीक्षा करें। जब वे बनाए जाते हैं, तो उन्हें क्रियान्वित किया जाता है, $.whenबस जारी रखने से पहले उन सभी का इंतजार किया जाता है।
रॉकेट हज़मत

1
अंतर के बारे में क्या $.when($, arrayOfPromises).done(...) और $.when(null, arrayOfPromises).done(...) (जो मैंने दोनों मंचों में प्रस्तावित समाधानों के रूप में पाया ...)
शून्यक्वेरा

63

$ .जब मापदंडों और निराकरण के किसी भी संख्या लेता है जब इन सब सुलझा ली है।

anyFunction .apply (thisValue, arrayParameters) कॉल समारोह anyFunction उसके संदर्भ की स्थापना (thisValue हो जाएगा इस कि समारोह कॉल के भीतर) और व्यक्तिगत पैरामीटर के रूप में arrayParameters में सभी वस्तुओं से गुजरता है।

उदाहरण के लिए:

$.when.apply($, [def1, def2])

के समान है:

$.when(def1, def2)

लेकिन कॉलिंग का लागू तरीका आपको अज्ञात संख्या के मापदंडों की एक सरणी को पारित करने की अनुमति देता है। (आपके कोड में, आप कह रहे हैं कि आप डेटा किसी सेवा से आते हैं, तो यह $ .when कॉल करने का एकमात्र तरीका है )


15

यहां, कोड पूरी तरह से प्रलेखित है।

// 1. Declare an array of 4 elements
var data = [1,2,3,4]; // the ids coming back from serviceA
// 2. Declare an array of Deferred objects
var processItemsDeferred = [];

// 3. For each element of data, create a Deferred push push it to the array
for(var i = 0; i < data.length; i++){
  processItemsDeferred.push(processItem(data[i]));
}

// 4. WHEN ALL Deferred objects in the array are resolved THEN call the function
//    Note : same as $.when(processItemsDeferred[0], processItemsDeferred[1], ...).then(everythingDone);
$.when.apply($, processItemsDeferred).then(everythingDone); 

// 3.1. Function called by the loop to create a Deferred object (data is numeric)
function processItem(data) {
  // 3.1.1. Create the Deferred object and output some debug
  var dfd = $.Deferred();
  console.log('called processItem');

  // 3.1.2. After some timeout, resolve the current Deferred
  //in the real world, this would probably make an AJAX call.
  setTimeout(function() { dfd.resolve() }, 2000);    

  // 3.1.3. Return that Deferred (to be inserted into the array)
  return dfd.promise();
}

// 4.1. Function called when all deferred are resolved
function everythingDone(){
  // 4.1.1. Do some debug trace
  console.log('processed all items');
}

7
$.when.apply($, array)जैसा है वैसा नहीं है $.when(array)। यह उसी तरह है:$.when(array[0], array[1], ...)
रॉकेट हज़मत

1
यही मुख्य कारण है .apply के साथ क्यों प्रयोग किया जाता है , आप नहीं जानते कि कई तत्वों की प्रक्रिया हो सकती है ।Deferred है
पाब्लो

2

दुर्भाग्य से मैं आप लोगों से सहमत नहीं हो सकता।

$.when.apply($, processItemsDeferred).always(everythingDone);

everythingDoneजैसे ही एक आस्थगित खारिज हो जाएगा, वैसे ही कॉल करेंगे , भले ही अन्य स्थगित हैं जो लंबित हैं

पूरी स्क्रिप्ट का जवाब दें (मैं http://jsfiddle.net/ ) सुझाता हूं :

var data = [1,2,3,4]; // the ids coming back from serviceA
var processItemsDeferred = [];

for(var i = 0; i < data.length; i++){
  processItemsDeferred.push(processItem(data[i]));
}

processItemsDeferred.push($.Deferred().reject());
//processItemsDeferred.push($.Deferred().resolve());

$.when.apply($, processItemsDeferred).always(everythingDone); 

function processItem(data) {
  var dfd = $.Deferred();
  console.log('called processItem');

  //in the real world, this would probably make an AJAX call.
  setTimeout(function() { dfd.resolve(); }, 2000);    

  return dfd.promise();
}

function everythingDone(){
  alert('processed all items');
}

यह एक बग? मैं इसे ऊपर वर्णित सज्जन की तरह उपयोग करना चाहूंगा।


1
पहला अस्वीकार हमेशा आग लगाएगा, लेकिन तब। मेरा jsfiddle.net/logankd/s5dacgb3 देखें जो मैंने आपके उदाहरण से बनाया है। मैं इस उदाहरण में JQuery 2.1.0 का उपयोग कर रहा हूं।
संरेखित

1
यह इच्छानुसार है। एक टन ऐसे मामले हैं जहाँ आप जानना चाहते हैं जैसे ही कुछ विफल होता है, असफल होने पर सब कुछ पूरा होने और जाँचने का इंतज़ार न करें। खासकर अगर प्रसंस्करण किसी भी विफलता के बाद जारी नहीं रह सकता है, तो बाकी के खत्म होने / असफल होने का इंतजार क्यों करें? जैसा कि अन्य टिप्पणी का सुझाव दिया गया है, आप .then या .fail & .done जोड़ी का उपयोग कर सकते हैं।
MPavlak

@GoneCoding यह उपयोगी नहीं है। ओपी ने पूछा कि क्या लागू होता है () करता है और आपने एक भयानक विकल्प सुझाया है जिसका उपयोग कभी नहीं किया जाना चाहिए :) कि आईएस नीचे वोट बटन क्या है। मैंने इसका उपयोग तब तक नहीं किया जब तक कि आप इसे प्रदान करने से इनकार क्यों नहीं कर रहे थे कि आपने ऐसा क्यों किया (किसी कारण से सरणियों से बचने के लिए आपकी प्राथमिकता से अधिक)
MPavlak

@GoneCoding उस जवाब को लेने के लिए धन्यवाद
MPavlak

1
@ गॉनकोडिंग लोल, मैंने आपका समाधान पढ़ा और प्रतिक्रिया प्रदान की। आपने मूल प्रश्न का उत्तर नहीं दिया। आप विस्तार से नहीं बता सकते थे कि ऐसा क्यों था। यह आपके जैसे लोग हैं जो सीखने वाले लोगों को भयानक समाधान प्रदान करते हैं। आपके पास स्पष्ट रूप से जावास्क्रिप्ट कौशल सीमित है और मुझे n00b होने के लिए ले जा रहा है। मैंने संकेत दिया कि यह गलत क्यों था और आप कोड भी नहीं पढ़ सकते थे और इसके बजाय मुझे बताएं कि मैं गलत हूं। अच्छा काम दोस्त!
MPavlak

1

शायद किसी को यह उपयोगी मिल सकता है:

$.when.apply($, processItemsDeferred).then(everythingDone).fail(noGood);

सब कुछ किसी भी अस्वीकार के मामले में नहीं कहा जाता है


0

$ .जब अकेले एक कॉलबैक के लिए संभव हो जाता है, तो कॉल किया जाता है जब इसे पारित किए गए प्रत्येक वादों को हल / अस्वीकार कर दिया जाता है। आम तौर पर, $ .जब तर्कों का एक चर संख्या लेता है, तो .apply इसे तर्कों का एक सरणी पास करना संभव बनाता है, यह बहुत शक्तिशाली है। .Apply पर अधिक जानकारी के लिए: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply


0

आपके सुरुचिपूर्ण समाधान के लिए धन्यवाद:

var promise;

for(var i = 0; i < data.length; i++){
  promise = $.when(promise, processItem(data[i]));
}

promise.then(everythingDone);

बस एक बिंदु: जब resolveWithकुछ मापदंडों को प्राप्त करने के लिए उपयोग किया जाता है, तो यह अपरिभाषित सेट के शुरुआती वादे के कारण टूट जाता है। मैंने इसे काम करने के लिए क्या किया:

// Start with an empty resolved promise - undefined does the same thing!
var promise;

for(var i = 0; i < data.length; i++){
  if(i==0) promise = processItem(data[i]);
  else promise = $.when(promise, processItem(data[i]));
}

promise.then(everythingDone);

2
जबकि यह काम करता है, यह वास्तव में सुरुचिपूर्ण नहीं है। आप ऐसे वादे तैयार कर रहे हैं जो अप-टू-आईथ डिफर्ड का प्रतिनिधित्व करते हैं ताकि अंतिम पुनरावृत्ति में "जब (वर्कटूडो [0..i-1], वर्कटूडो [आई])" या अधिक स्पष्ट रूप से हो जब सभी पिछले काम और यह काम हो गया"। इसका मतलब है कि आपके पास मेरे वादों पर रैपर होने पर i + 1 है। इसके अलावा, इस प्रकार का सामान बनाते समय, बस पहले पुनरावृत्ति को खोल दें। var वादा = processItem (डेटा [0]); के लिए (var i = 1; i <data.length; i ++) {वादा = $ .जब (वादा, processItem (डेटा [i])); }
MPavlak
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.