[javascript] 지연된 배열을 $ .when ()에 전달

여기에 무슨 일이 일어나고 있는지에 대한 고안된 예가 있습니다 : http://jsfiddle.net/adamjford/YNGcm/20/

HTML :

<a href="#">Click me!</a>
<div></div>

자바 스크립트 :

function getSomeDeferredStuff() {
    var deferreds = [];

    var i = 1;
    for (i = 1; i <= 10; i++) {
        var count = i;

        deferreds.push(
        $.post('/echo/html/', {
            html: "<p>Task #" + count + " complete.",
            delay: count
        }).success(function(data) {
            $("div").append(data);
        }));
    }

    return deferreds;
}

$(function() {
    $("a").click(function() {
        var deferreds = getSomeDeferredStuff();

        $.when(deferreds).done(function() {
            $("div").append("<p>All done!</p>");
        });
    });
});

나는 “모두 끝났어!” 모든 지연된 작업이 완료된 후에 표시되지만 $.when()지연된 개체 배열을 처리하는 방법을 알지 못하는 것 같습니다. “다됐다!” 배열이 Deferred 객체가 아니기 때문에 먼저 발생하므로 jQuery가 진행되어 방금 완료된 것으로 가정합니다.

나는 객체를 함수에 전달할 수 있다는 것을 알고 $.when(deferred1, deferred2, ..., deferredX)있지만 해결하려는 실제 문제에서 얼마나 많은 지연 객체가 실행 될지 알 수 없습니다.



답변

에 값의 배열을 전달하려면 어떤 일반적으로 그들에게 별도의 매개 변수를 사용하는 것으로 기대하는 기능 Function.prototype.apply이 경우에 당신이 필요합니다 :

$.when.apply($, my_array).then( ___ );

http://jsfiddle.net/YNGcm/21/ 참조

ES6에서는 ... 스프레드 연산자를 대신 사용할 수 있습니다 .

$.when(...my_array).then( ___ );

두 경우 모두 .then처리기에 필요한 공식 매개 변수의 수를 미리 알지 못할 가능성이 높으므로 arguments해당 약속의 결과를 검색하려면 해당 처리기가 배열 을 처리해야합니다 .


답변

(감사합니다!) 위의 해결 방법은 제대로의 연기에 제공되는 객체 돌아 가지의 문제를 해결하지 않는 resolve()jQuery를가 호출 때문에 방법 done()fail()각각의 매개 변수가 아닌 배열과 콜백을. 즉, arguments의사 배열 을 사용하여 지연된 배열에서 반환 된 모든 확인 / 거부 된 개체를 가져와야합니다.

$.when.apply($,deferreds).then(function() {
     var objects=arguments; // The array of resolved objects as a pseudo-array
     ...
};

지연된 배열을 전달 했으므로 결과 배열을 다시 가져 오는 것이 좋습니다. 의사 배열 대신 실제 배열을 다시 가져 와서 같은 메소드를 사용할 수도 있습니다 Array.sort().

다음은 이러한 문제를 해결 하는 when.jswhen.all()방법에서 영감을 얻은 솔루션입니다 .

// Put somewhere in your scripting environment
if (typeof jQuery.when.all === 'undefined') {
    jQuery.when.all = function (deferreds) {
        return $.Deferred(function (def) {
            $.when.apply(jQuery, deferreds).then(
                function () {
                    def.resolveWith(this, [Array.prototype.slice.call(arguments)]);
                },
                function () {
                    def.rejectWith(this, [Array.prototype.slice.call(arguments)]);
                });
        });
    }
}

이제 지연 / 프로 미스 배열을 전달하고 콜백에서 해결 / 거부 된 오브젝트 배열을 다음과 같이 다시 가져올 수 있습니다.

$.when.all(deferreds).then(function(objects) {
    console.log("Resolved objects:", objects);
});


답변

when메소드를 배열에 적용 할 수 있습니다 .

var arr = [ /* Deferred objects */ ];

$.when.apply($, arr);

일련의 jQuery 연기로 어떻게 작업합니까?


답변

여러 개의 병렬 AJAX 호출을 호출 할 때 각 응답을 처리하기위한 두 가지 옵션이 있습니다.

  1. 동기식 AJAX 호출을 사용하십시오.
  2. Promises'array를 사용 하고 s $.when를 수락 promise하고 .done모든 promise응답이 각 응답으로 성공적으로 반환 되면 콜백 이 호출됩니다 .

function ajaxRequest(capitalCity) {
   return $.ajax({
        url: 'https://restcountries.eu/rest/v1/capital/'+capitalCity,
        success: function(response) {
        },
        error: function(response) {
          console.log("Error")
        }
    });
}
$(function(){
   var capitalCities = ['Delhi', 'Beijing', 'Washington', 'Tokyo', 'London'];
   $('#capitals').text(capitalCities);

   function getCountryCapitals(){ //do multiple parallel ajax requests
      var promises = [];
      for(var i=0,l=capitalCities.length; i<l; i++){
            var promise = ajaxRequest(capitalCities[i]);
            promises.push(promise);
      }

      $.when.apply($, promises)
        .done(fillCountryCapitals);
   }

   function fillCountryCapitals(){
        var countries = [];
        var responses = arguments;
        for(i in responses){
            console.dir(responses[i]);
            countries.push(responses[i][0][0].nativeName)
        }
        $('#countries').text(countries);
   }

   getCountryCapitals()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <h4>Capital Cities : </h4> <span id="capitals"></span>
  <h4>Respective Country's Native Names : </h4> <span id="countries"></span>
</div>


답변

필요없는 간단한 대안으로 $.when.apply또는 array여러 병렬 약속에 대한 하나의 약속을 생성하기 위해 다음과 같은 패턴을 사용할 수 있습니다 :

promise = $.when(promise, anotherPromise);

예 :

function GetSomeDeferredStuff() {
    // Start with an empty resolved promise (or undefined does the same!)
    var promise;
    var i = 1;
    for (i = 1; i <= 5; i++) {
        var count = i;

        promise = $.when(promise,
        $.ajax({
            type: "POST",
            url: '/echo/html/',
            data: {
                html: "<p>Task #" + count + " complete.",
                delay: count / 2
            },
            success: function (data) {
                $("div").append(data);
            }
        }));
    }
    return promise;
}

$(function () {
    $("a").click(function () {
        var promise = GetSomeDeferredStuff();
        promise.then(function () {
            $("div").append("<p>All done!</p>");
        });
    });
});

노트:

  • 나는 누군가 체인을 사용하여 순차적으로 약속을보고 나서 이것을 알아 냈습니다. promise = promise.then(newpromise)
  • 단점은 씬 뒤에 여분의 약속 객체를 만들고 끝에 전달 된 매개 변수는 유용하지 않습니다 (추가 객체 안에 중첩되어 있기 때문에). 짧고 간단하지만 원하는 것을 위해.
  • 단점은 어레이 또는 어레이 관리가 필요하지 않다는 것입니다.

답변

$ .each를 사용하여 다른 것을 제안하고 싶습니다.

  1. 우리는 다음과 같이 아약스 함수를 선언 할 수있다 :

    function ajaxFn(someData) {
        this.someData = someData;
        var that = this;
        return function () {
            var promise = $.Deferred();
            $.ajax({
                method: "POST",
                url: "url",
                data: that.someData,
                success: function(data) {
                    promise.resolve(data);
                },
                error: function(data) {
                    promise.reject(data);
                }
            })
            return promise;
        }
    }
  2. 우리가 보낼 아약스로 함수 배열을 생성하는 코드의 일부 :

    var arrayOfFn = [];
    for (var i = 0; i < someDataArray.length; i++) {
        var ajaxFnForArray = new ajaxFn(someDataArray[i]);
        arrayOfFn.push(ajaxFnForArray);
    }
  3. 그리고 아약스를 전송하여 함수를 호출 :

    $.when(
        $.each(arrayOfFn, function(index, value) {
            value.call()
        })
    ).then(function() {
            alert("Cheer!");
        }
    )

답변

코드를 변환하고 ES6에 액세스 할 수있는 경우 객체의 반복 가능한 각 항목을 개별 인수로 구체적으로 적용하는 스프레드 구문을 $.when()필요에 따라 사용할 수 있습니다.

$.when(...deferreds).done(() => {
    // do stuff
});

MDN 링크-확산 구문