$ .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
Kevin B

2
fwiw, _.when사용하지 않아도되도록 단일 어레이를 전달할 수있는 밑줄에 지연된 포트 가 있습니다.apply
Eevee 2013



1
OP가 그의 첫 문장에서 언급 한 기사는 위치를 옮겼 습니다 . 현재 위치는 flaviocopes.com/blog/deferreds-and-promises-in-javascript 입니다.
glaucon 2015 년

답변:


161

.apply인수 배열로 함수를 호출하는 데 사용됩니다. 배열의 각 요소를 취하고 각 요소를 함수의 매개 변수로 사용합니다. 함수 내 .apply에서 컨텍스트 ( this)를 변경할 수도 있습니다 .

그래서 $.when. "이 모든 약속이 해결되면 ... 무언가를하라"는 말이 사용됩니다. 무한한 (가변) 수의 매개 변수를 사용합니다.

귀하의 경우에는 일련의 약속이 있습니다. 얼마나 많은 매개 변수를 전달하는지 알 수 없습니다 $.when. 배열 자체를에 전달하는 $.when것은 매개 변수가 배열이 아니라 약속 일 것으로 예상하기 때문에 작동하지 않습니다.

그것이 .apply들어오는 곳 입니다. 그것은 배열을 취하고 $.when각 요소를 매개 변수로 호출합니다 (그리고가 / this로 설정되어 있는지 확인합니다 ), 그러면 모두 작동합니다 :-)jQuery$


3
$ .when 메서드에 여러 promise가 전달 될 때. 어떤 순서로 실행됩니까? 차례로 또는 병렬로?
Darshan 2013

21
@Darshan : 당신은 약속을 "실행"하지 않습니다. 당신은 그들이 해결되기를 기다립니다. 생성 될 때 실행 $.when되며 계속하기 전에 모두 완료 될 때까지 기다립니다.
Rocket Hazmat

1
의 차이에 대해 무엇을 $.when($, arrayOfPromises).done(...) 하고 $.when(null, arrayOfPromises).done(...) (나는 ... 포럼에서 제안 된 솔루션으로 모두 발견)
zeroquaranta

63

$ .when 은 여러 매개 변수를 취하고 이러한 매개 변수 모두 해결 되면 해결됩니다.

anyFunction .apply (thisValue, arrayParameters) 는 컨텍스트를 설정하는 anyFunction 함수를 호출합니다 (thisValue는 this 그 함수 호출 내)를 개별 파라미터로서 arrayParameters 모든 객체를 전달한다.

예를 들면 :

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

와 같다:

$.when(def1, def2)

그러나 apply 호출 방식을 사용하면 알 수없는 수의 매개 변수 배열을 전달할 수 있습니다. (귀하의 코드에서 데이터 는 서비스에서 제공되며 $ .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], ...)
Rocket Hazmat 2013

1
그것이 .apply 와 함께 사용되는 주된 이유입니다. processItemsDeferred가 가지고있는 많은 요소를 모릅니다
Pablo

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
첫 번째 거부는 항상 실행되지만 .then은 실행되지 않습니다. 귀하의 예제에서 만든 jsfiddle.net/logankd/s5dacgb3 를 참조하십시오 . 이 예제에서는 JQuery 2.1.0을 사용하고 있습니다.
정렬

1
이것은 의도 한 것입니다. 모든 것이 완료 될 때까지 기다리지 않고 실패가 있는지 확인하지 않고 무언가 가 실패 하자마자 알고 싶은 경우가 많습니다 . 특히 실패 후 처리를 계속할 수없는 경우 나머지가 완료 / 실패 할 때까지 기다리는 이유는 무엇입니까? 다른 의견이 제안했듯이 .then 또는 .fail & .done 쌍을 사용할 수 있습니다.
MPavlak

@GoneCoding 유용하지 않습니다. OP는 apply ()가 무엇을하는지 물었고 절대 사용해서는 안되는 끔찍한 대안을 제안했습니다. 나는 또한 당신이 그 이유를 제공하기를 거부 할 때까지 그것을 사용하지 않았습니다 (어떤 이유로 배열을 피하는 것을 선호하는 것보다 더)
MPavlak

@GoneCoding 답변을 내려 주셔서 감사합니다
MPavlak

1
@GoneCoding lol, 솔루션을 읽고 피드백을 제공했습니다. 원래 질문에 대한 답변을 제공하지 않았습니다. 왜 그랬는지 설명 할 수 없었습니다. 배우는 사람들에게 끔찍한 해결책을 제공하는 것은 여러분과 같은 사람들입니다. 당신은 분명히 제한된 자바 스크립트 기술을 가지고 있으며 나를 n00b로 데려 가고 있습니다. 나는 그것이 왜 잘못되었는지를 나타내었고 당신은 코드를 읽을 수조차 없었고 대신 내가 틀렸다고 말해주었습니다. 잘 했어 친구!
MPavlak

1

누군가 유용하게 사용할 수 있습니다.

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

거부의 경우 everythingDone이 호출되지 않습니다.



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
작동하지만 정말 우아하지는 않습니다. 당신은 마지막 반복이 "when (workToDo [0..i-1], workToDo [i])"를 포함하거나 더 분명하게 "모든 이전 작업과 작업이 완료되었습니다. " 이것은 약속을 래퍼 할 때 i + 1이 있음을 의미합니다. 또한 이런 종류의 작업을 수행 할 때 첫 번째 반복을 간단히 풀면됩니다. var promise = processItem (data [0]); for (var i = 1; i <data.length; i ++) {promise = $ .when (promise, processItem (data [i])); }
MPavlak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.