$ .When.apply ($, someArray) ne yapar?


110

Ertelenen ve Sözler hakkında okuyorum ve karşıma çıkmaya devam ediyorum $.when.apply($, someArray). Bunun tam olarak ne yaptığından biraz emin değilim, bir satırın tam olarak çalıştığına dair bir açıklama arıyorum (kod parçacığının tamamı değil). İşte bazı bağlam:

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().thenbu durumda yerine kullanılabilir , sadece Bilginize
Kevin B

2
fwiw, tek bir diziyi _.whenkullanmanıza gerek kalmaması için altını çizmek için bir Ertelenmiş bağlantı noktası varapply
Eevee

Şu konuda daha fazla bilgi edinin .apply: developer.mozilla.org/en-US/docs/JavaScript/Reference/… .
Felix Kling


1
OP'nin ilk cümlesinde değindiği makale yerleri değiştirdi - şimdi şu adreste: flaviocopes.com/blog/deferreds-and-promises-in-javascript .
glaucon

Yanıtlar:


161

.applybir dizi argüman içeren bir işlevi çağırmak için kullanılır. Dizideki her bir öğeyi alır ve her birini işleve bir parametre olarak kullanır. bir işlevin içindeki .applybağlamı da ( this) değiştirebilir .

Öyleyse alalım $.when. "Bütün bu sözler çözüldüğünde ... bir şeyler yap" derdi. Sonsuz (değişken) sayıda parametre alır.

Senin durumunda, bir dizi sözün var; kaç parametreye geçtiğinizi bilmiyorsunuz $.when. Dizinin kendisini iletmek $.whenişe yaramaz çünkü parametrelerinin bir dizi değil vaatler olmasını bekler.

Yani en .applyIt dizi alır ve aramaları. Gelir $.whenparametre olarak her eleman ile (ve emin olur thisayarlandığında jQuery/ ' $o kadar sonra, bütün işleri :-))


3
$ .when metoduna birden fazla vaat geçtiğinde. Hangi sırayla yürütecekler? birbiri ardına mı yoksa paralel mi?
Darshan

21
@Darshan: Sözleri "kaçırmıyorsun". Onların çözülmesini bekliyorsunuz. Oluşturulduklarında çalıştırılırlar, $.whendevam etmeden önce hepsinin bitmesini beklerler.
Rocket Hazmat

1
peki $.when($, arrayOfPromises).done(...) ve arasındaki fark $.when(null, arrayOfPromises).done(...) (her ikisini de forumlarda önerilen çözümler olarak buldum ...)
zeroquaranta

63

$ .her parametre ve giderir herhangi bir sayıda alır zaman tüm bu çözdük.

anyFunction .apply (thisValue, arrayParameters) işlevini çağırır anyFunction Bağlamını ayarı (thisValue olacak bu o işlev çağrısı içinde) ve bireysel parametre olarak arrayParameters tüm nesneleri geçirir.

Örneğin:

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

Aynıdır:

$.when(def1, def2)

Ancak arama yapmanın uygulama yolu, bilinmeyen sayıda parametre dizisini iletmenize izin verir. (Kodunuzda, verilerinizin bir servisten geldiğini söylüyorsunuz , o zaman $ .when aramanın tek yolu budur )


15

Burada kod tamamen belgelenmiştir.

// 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)ile aynı değil$.when(array) . $.when(array[0], array[1], ...)
Şununla

1
İşte bu nedenle, kullanılan ana sebebidir .apply , sen processItemsDeferred sahip birçok unsurları hoy bilmiyorum
Pablo

2

Maalesef sizinle aynı fikirde olamıyorum.

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

Bekleyen başka ertelemeler olsa bile, everythingDoneertelenen biri reddedilir reddedilmez arayacaktır .

İşte tam komut dosyası ( 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');
}

Bu bir hata mı? Bunu beyefendinin anlattığı gibi kullanmak istiyorum.


1
İlk red her zaman tetiklenir, ancak. Sonra değil. Örneğinizden yaptığım jsfiddle.net/logankd/s5dacgb3'üme bakın . Bu örnekte JQuery 2.1.0 kullanıyorum.
Bağlantısızlar

1
Bu amaçlandığı gibi. Bir şeyler başarısız olur olmaz bilmek isteyeceğiniz , her şeyin tamamlanmasını beklemeyeceğiniz ve arıza olup olmadığını kontrol edeceğiniz tonlarca durum vardır. Özellikle de herhangi bir hatadan sonra işleme devam edemiyorsa, geri kalanının bitmesini / başarısız olmasını neden bekleyesiniz? Diğer yorumun önerdiği gibi, .then veya .fail & .done çiftini kullanabilirsiniz.
MPavlak

@GoneCoding Faydalı değil. OP, apply () 'ın ne işe yaradığını sordu ve siz asla kullanılmaması gereken korkunç bir alternatif önerdiniz :) bu, aşağı oylama düğmesi bunun içindir. Ayrıca NEDEN bunu neden yaptığınızı belirtmeyi reddedinceye kadar kullanmadım (herhangi bir nedenle dizilerden kaçınmak için tercihinizden daha fazlası)
MPavlak

@GoneCoding Cevabı aldığınız için teşekkür ederiz
MPavlak

1
@GoneCoding lol, çözümünüzü okudum ve geri bildirimde bulundum. orijinal soruya bir cevap vermediniz. Neden olduğu gibi olduğunu açıklayamazsın. Öğrenen insanlara korkunç çözümler sunan sizin gibi insanlar. Açıkça sınırlı javascript beceriniz var ve beni n00b olmaya götürüyorsunuz. Neden yanlış olduğunu söyledim ve kodu bile okuyamıyorsunuz ve bunun yerine bana yanıldığımı söylüyorsunuz. iyi iş dostum!
MPavlak

1

Belki birisi bunu yararlı bulabilir:

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

EverythingDone herhangi bir reddedilme durumunda çağrılmaz



0

Zarif çözümünüz için teşekkürler:

var promise;

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

promise.then(everythingDone);

Sadece bir nokta: resolveWithBazı parametreleri almak için kullanılırken , ilk sözün tanımsız olarak ayarlanması nedeniyle bozulur. Çalışması için ne yaptım:

// 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
Bu işe yarasa da, gerçekten zarif değil. Önceki tüm çalışmalar ve bu iş bitti". Bu, sözlerinizi sarmaladığınızda i + 1'iniz olduğu anlamına gelir. Ayrıca, bu tür şeyler yaparken ilk yinelemeyi açmanız yeterlidir. var promise = processItem (veri [0]); for (var i = 1; i <data.length; i ++) {promise = $ .when (promise, processItem (data [i])); }
MPavlak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.