2014-07-11 10 views
9

나는 간단한 URL 배열을 가지고 있는데, 각각 jQuery로로드하고 싶다. $.get을 사용하고 있었지만 $.Deferred으로 작동하지 않을 수 있으므로 $.ajax으로 전환했습니다. 거의 작동하지만 결과는 이상합니다. 누군가가 내가이 일을 더 잘하도록 도와 줄 수 있기를 바랬다.

var results = [], files = [ 
    'url1', 'url2', 'url3' 
]; 

$.when(
    $.ajax(files[0]).done(function(data) { 
     results.push(data); console.log("step 1.0"); 
    }), 
    $.ajax(files[1]).done(function(data) { 
     results.push(data); console.log("step 1.1"); 
    }), 
    $.ajax(files[2]).done(function(data) { 
     results.push(data); console.log("step 1.2"); 
    }) 
).then(function(){ 
    console.log("step 2"); 
}); 

이 출력해야 ..

  • 단계 1.0
  • 단계 1.1
  • 단계 1.2
  • 다음 results 배열의 결과를 포함 2

단계 모두 3 건의 아약스 요청. 이것이 가능한가?

+1

이 문제는 무엇입니까? 요청은 다른 순서로 완료 될 수 있으므로'1.2 단계, 1.0 단계, 1.1 단계, 2 단계 '로 끝날 수 있지만 배열은'then()'이 실행되기 전에 항상 채워질 것입니다. –

+0

나는 올바른 순서로 완성해야한다. 코드가 올바르게 작동하는 것이 중요합니다. – Ciel

+0

다른 결과가 나타납니다.나는 1 단계 중 어느 단계보다 먼저 2 단계를 발사합니다. – Ciel

답변

8

첫째을 .when에 전달 된 것과 같은 순서에있을 것입니다 그 때는 전달

var results = [], files = [ 
    'url1', 'url2', 'url3' 
]; 

$.when.apply($, $.map(files, function (file) { 
    return $.ajax(file); 
})).then(function (dataArr) { 
    /* 
    * dataArr is an array of arrays, 
    * each array contains the arguments 
    * returned to each success callback 
    */ 
    results = $.map(dataArr, function (data) { 
     return data[0]; // the first argument to the success callback is the data 
    }); 
    console.log(results); 
}); 

인수는, 당신은 당신이 (당신의 세 아약스가 병렬로 처리 할 호출 할 경우 결정해야 전체 실행 시간은 줄이면서 같은 시간에 모두 실행) 또는 하나의 아약스 호출이 실행되고 순서대로 완료되면 다음 아약스 호출을 시작합니다. 이것은 당신이 어떻게하는지에 영향을주는 중요한 설계 결정입니다.

$.when()을 사용하면 세 가지 아약스 호출이 모두 병렬로 실행됩니다. 모든 결과가 완료된 경우에만 결과를 검토하면 결과를 특정 순서로 처리 할 수 ​​있습니다. 모든 결과를 사용할 수 있고 요청한 순서대로 사용할 수있을 때만 처리하므로 결과를 특정 순서로 처리 할 수 ​​있습니다. 그러나 이렇게하면 모든 아약스 호출이 처음에 즉시 전송됩니다. 이렇게하면보다 완벽한 엔드 투 엔드 (end-to-end) 시간을 얻을 수 있으므로 요청 유형에 적합하면 일반적으로이를 수행하는 것이 더 좋습니다.

그 작업을 수행하려면, 당신은 당신이 이런 일에 무엇을 재구성 할 수 있습니다 : 당신이 호출 된 $.when()에 대한 .done() 핸들러 때까지 기다리고 있기 때문에

병렬
var files = [ 
    'url1', 'url2', 'url3' 
]; 

$.when($.ajax(files[0]),$.ajax(files[1]),$.ajax(files[2])).done(function(a1, a2, a3) { 
    var results = []; 
    results.push(a1[0]); 
    results.push(a2[0]); 
    results.push(a3[0]); 
    console.log("got all results") 
}); 
에서

실행 모든 아약스 결과는 즉시 준비가되며 요청 된 순서대로 $.when()으로 표시되므로 (실제로 어느 것이 먼저 끝났는지에 관계없이) 결과를 가능한 빨리 얻고 예측 가능한 순서로 표시됩니다.

results 어레이의 정의를 $.when() 처리기로 옮겼습니다. 그 이유는 데이터가 실제로 (타이밍상의 이유로) 유효하다는 것을 알고 있기 때문입니다.병렬에서


실행 - 당신은 더 이상 배열을 가지고 있다면, 당신은 더 나은 아니라 루프에서 모두 처리 할 .map() 같은 것을 사용하여 배열을 통해 반복 찾을 수있는 임의의 길이의 배열

을 반복 개별적으로 나열하는 것보다 :

var files = [ 
    'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7' 
]; 

$.when.apply($, files.map(function(url) { 
    return $.ajax(url); 
})).done(function() { 
    var results = []; 
    // there will be one argument passed to this callback for each ajax call 
    // each argument is of this form [data, statusText, jqXHR] 
    for (var i = 0; i < arguments.length; i++) { 
     results.push(arguments[i][0]); 
    } 
    // all data is now in the results array in order 
}); 

순서 Ajax 호출

반면에 실제로 두 번째 호출이 시작될 때까지 두 번째 호출이 시작되지 않도록하려면 첫 번째 호출이 완료 될 때까지 두 번째 ajax 호출에 결과가 필요한 경우 필요한 것일 수 있습니다. 첫 번째 ajax 호출을 사용하여 요청 또는 수행 할 작업을 알면 완전히 다른 디자인 패턴이 필요하며 $.when()은 진행 방법이 아닙니다 (병렬 요청 만 수행함). 이 경우 결과를 x.then().then()으로 연결하기를 원할 것입니다. 그런 다음 요청한 순서대로 로그 문을 출력 할 수 있습니다.

$.ajax(files[0]).then(function(data0) { 
     console.log("step 1.0"); 
     return $.ajax(files[1]); 
    }).then(function(data1) { 
     console.log("step 1.1"); 
     return $.ajax(files[2]); 
    }).done(function(data2) { 
     console.log("step 1.2"); 
     // all the ajax calls are done here 
     console.log("step 2"); 
    }); 

콘솔 출력은 :

step 1.0 
step 1.1 
step 1.2 
step 2 

이 구조 또한 파일의 배열이 이상하면 자동으로 N 연속 아약스 호출을 실행하는 루프에 투입 될 수있다. results 배열에 들어갈 때 결과를 수집 할 수 있지만, 순차적으로 수행되는 이유는 다음 결과가 다음 ajax 호출에 의해 소비되므로 종종 최종 결과 만 필요하기 때문입니다. 결과를 수집하려면 각 단계에서 배열을 results 배열로 밀어 넣을 수 있습니다.

중첩의 동일한 최상위 수준에 머무르면서 더 이상 중첩되지 않는 상태에서 작업을 시퀀싱 할 수 있다는 이점이 있습니다.


순서 아약스는 호출 - 반복 임의의 길이의 배열 여기

이 순서 루프에서 같을 것이다 무엇 :

var files = [ 
    'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7' 
]; 

var results = []; 
files.reduce(function(prev, cur, index) { 
    return prev.then(function(data) { 
     return $.ajax(cur).then(function(data) { 
      console.log("step 1." + index); 
      results.push(data); 
     }); 
    }) 
}, $().promise()).done(function() { 
    // last ajax call done 
    // all results are in the results array 
    console.log("step 2.0"); 
}); 

콘솔 출력 :

step 1.0 
step 1.1 
step 1.2 
step 1.3 
step 1.4 
step 1.5 
step 1.6 
step 2 

Array.prototype.reduce() 방법은 각 배열 요소에 대해 .then()을 추가 할 때 수행해야하는 각각의 배열 요소를 처리 할 때 단일 값을 누적하기 때문에 여기에 직접 입력해야합니다. .reduce() 반복은 $().promise()과 함께 빈/해결 된 약속으로 시작됩니다 (다른 약속도 만들 수있는 방법이 있습니다). 이는 이미 해결 된 .then()을 시작하기위한 것입니다.

+0

이것은 매우 유용합니다. 가능한 오버 헤드가있을지라도 외부 라이브러리 사용에 대한 지혜를보기 시작했습니다. 지금 당장은 한 곳에서해야하지만, 두 번 이상해야한다면, 기능을 보충하기위한 추가 작업이 더 많이 발생하게됩니다. – Ciel

+0

@Ciel - 귀하의 의견을 이해할 수 없습니다. 외부 라이브러리가 필요한 이유는 무엇입니까? 이러한 옵션을 몇 줄만 추가하면 재사용 가능한 함수로 만들 수 있습니다. – jfriend00

+0

죄송합니다. 나는 약간 산만 해졌고, 오직 오늘 만이 사실을 실제로 시험해 볼 기회를 얻었습니다. 모든 도움을 주셔서 고맙습니다.이 예제만으로 많은 것을 배웠습니다. – Ciel

2

각 .done 대신 .then에서 반환 값에 액세스해야합니다. 또한 .map은 친구입니다. 그들이

+1

'$ .when()'의 데이터를 제대로 처리하지 못한다고 생각합니다. 배열의 배열 인 단일 인수를 제공하지 않습니다. 그것은 각 인수가 세 값의 배열 인 일련의 인수를 제공합니다. 마지막 코드 예제는 http://api.jquery.com/jquery.when/ 3 행을 참조하십시오. – jfriend00