[Javascript] Deferreds की एक सरणी में $ .when ()


Answers

उपरोक्त कामकाज (धन्यवाद!) स्थगित की resolve() विधि को प्रदान की गई वस्तुओं को वापस पाने की समस्या का सही ढंग से समाधान नहीं करते हैं क्योंकि jQuery अलग-अलग पैरामीटर के साथ done() और fail() कॉलबैक को कॉल करता done() , एक सरणी नहीं। इसका मतलब है कि हमें अवशेषों की सरणी द्वारा लौटाई गई सभी हल / अस्वीकृत वस्तुओं को प्राप्त करने के लिए arguments छद्म-सरणी का उपयोग करना होगा, जो बदसूरत है:

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

चूंकि हम स्थगित की एक सरणी में पारित हुए हैं, इसलिए परिणाम की एक सरणी वापस लेना अच्छा लगेगा। छद्म-सरणी के बजाय वास्तविक सरणी वापस लेना भी अच्छा होगा ताकि हम Array.sort() जैसी विधियों का उपयोग कर सकें।

यहां एक समाधान है जब.जेएस की when.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);
});
Question

यहां क्या हो रहा है इसका एक संक्षिप्त उदाहरण दिया गया है: 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() यह नहीं पता कि डिफरर्ड ऑब्जेक्ट्स की सरणी को कैसे संभाला जाए। "सब कुछ कर दिया!" पहले हो रहा है क्योंकि सरणी एक विकृत वस्तु नहीं है, इसलिए jQuery आगे बढ़ता है और मानता है कि यह अभी किया गया है।

मुझे पता है कि कोई ऑब्जेक्ट को $.when(deferred1, deferred2, ..., deferredX) जैसे फ़ंक्शन में पास कर सकता है $.when(deferred1, deferred2, ..., deferredX) लेकिन यह अज्ञात है कि वास्तविक समस्या में निष्पादन पर कितनी डिफरर्ड ऑब्जेक्ट्स निष्पादित हो रही हैं, जिसे मैं हल करने का प्रयास कर रहा हूं।




मैं $ .each का उपयोग करने के साथ दूसरे को प्रस्तावित करना चाहता हूं:

  1. हम AJAX फ़ंक्शन घोषित कर सकते हैं जैसे:

    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. कोड का एक हिस्सा जहां हम भेजने के लिए AJAX के साथ कार्यों की सरणी बनाते हैं:

    var arrayOfFn = [];
    for (var i = 0; i < someDataArray.length; i++) {
        var ajaxFnForArray = new ajaxFn(someDataArray[i]);
        arrayOfFn.push(ajaxFnForArray);
    }
    
  3. और AJAX भेजने के साथ कार्यों को बुलाओ:

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



मेरे पास एक मामला बहुत समान था जहां मैं प्रत्येक लूप में पोस्ट कर रहा था और फिर AJAX से प्राप्त संख्याओं से कुछ फ़ील्ड में HTML मार्कअप सेट कर रहा था। इसके बाद मुझे इन क्षेत्रों के (अब-अपडेटेड) मानों का योग करने की आवश्यकता थी और कुल क्षेत्र में जगह थी।

इस प्रकार समस्या यह थी कि मैं सभी संख्याओं पर एक योग करने की कोशिश कर रहा था लेकिन एसिंक अजाक्स कॉल से अभी तक कोई डेटा वापस नहीं आया था। कोड को पुन: उपयोग करने में सक्षम होने के लिए मुझे कुछ कार्यक्षमताओं में इस कार्यक्षमता को पूरा करने की आवश्यकता थी। मेरा बाहरी कार्य डेटा जाने का इंतजार कर रहा है इससे पहले कि मैं जाता हूं और पूरी तरह से अद्यतन डीओएम के साथ कुछ सामान करता हूं।

    // 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;
    }



एकाधिक समांतर AJAX कॉल को कॉल करते समय, आपके पास संबंधित प्रतिक्रियाओं को संभालने के लिए दो विकल्प होते हैं।

  1. सिंक्रोनस AJAX कॉल / एक के बाद एक / अनुशंसित का उपयोग करें
  2. Promises' सरणी और $.when उपयोग करें $.when जो promise और उसके कॉलबैक को स्वीकार promise जब सभी promise संबंधित प्रतिक्रियाओं के साथ सफलतापूर्वक वापस आते हैं तो उन्हें .done जाता है।

उदाहरण

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>