development

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

big-blog 2020. 2. 18. 22:46
반응형

지연된 배열을 $ .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을 사용 하고을 $.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 링크-확산 구문


angularJS 또는 Q promise 라이브러리의 변형을 사용하는 .all()경우이 정확한 문제를 해결 하는 방법이 있습니다.

var savePromises = [];
angular.forEach(models, function(model){
  savePromises.push(
    model.saveToServer()
  )
});

$q.all(savePromises).then(
  function success(results){...},
  function failed(results){...}
);

전체 API를 참조하십시오 :

https://github.com/kriskowal/q/wiki/API-Reference#promiseall

https://docs.angularjs.org/api/ng/service/$q


각 루프에 게시 한 다음 아약스에서받은 숫자의 일부 필드에서 html 마크 업을 설정하는 경우와 매우 비슷한 경우가있었습니다. 그런 다음이 필드의 (현재 업데이트 된) 값의 합계를 수행하고 총 필드에 배치해야했습니다.

따라서 문제는 모든 숫자에 대한 합계를 시도했지만 비동기 ajax 호출에서 아직 데이터가 도착하지 않았다는 것입니다. 코드를 재사용하려면 몇 가지 기능으로이 기능을 완료해야했습니다. 내 외부 함수는 데이터를 기다린 다음 완전히 업데이트 된 DOM으로 작업을 수행합니다.

    // 1st
    function Outer() {
        var deferreds = GetAllData();

        $.when.apply($, deferreds).done(function () {
            // now you can do whatever you want with the updated page
        });
    }

    // 2nd
    function GetAllData() {
        var deferreds = [];
        $('.calculatedField').each(function (data) {
            deferreds.push(GetIndividualData($(this)));
        });
        return deferreds;
    }

    // 3rd
    function GetIndividualData(item) {
        var def = new $.Deferred();
        $.post('@Url.Action("GetData")', function (data) {
            item.html(data.valueFromAjax);
            def.resolve(data);
        });
        return def;
    }

참고 URL : https://stackoverflow.com/questions/5627284/pass-in-an-array-of-deferreds-to-when



도와주세요.
반응형