Pass in an array of Deferreds to $.when()

后端 未结 9 1193
伪装坚强ぢ
伪装坚强ぢ 2020-11-21 22:20

Here\'s an contrived example of what\'s going on: http://jsfiddle.net/adamjford/YNGcm/20/

HTML:

Click me!
&l
相关标签:
9条回答
  • 2020-11-21 22:33

    The workarounds above (thanks!) don't properly address the problem of getting back the objects provided to the deferred's resolve() method because jQuery calls the done() and fail() callbacks with individual parameters, not an array. That means we have to use the arguments pseudo-array to get all the resolved/rejected objects returned by the array of deferreds, which is ugly:

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

    Since we passed in an array of deferreds, it would be nice to get back an array of results. It would also be nice to get back an actual array instead of a pseudo-array so we can use methods like Array.sort().

    Here is a solution inspired by when.js's when.all() method that addresses these problems:

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

    Now you can simply pass in an array of deferreds/promises and get back an array of resolved/rejected objects in your callback, like so:

    $.when.all(deferreds).then(function(objects) {
        console.log("Resolved objects:", objects);
    });
    
    0 讨论(0)
  • 2020-11-21 22:35

    You can apply the when method to your array:

    var arr = [ /* Deferred objects */ ];
    
    $.when.apply($, arr);
    

    How do you work with an array of jQuery Deferreds?

    0 讨论(0)
  • 2020-11-21 22:36

    If you're using angularJS or some variant of the Q promise library, then you have a .all() method that solves this exact problem.

    var savePromises = [];
    angular.forEach(models, function(model){
      savePromises.push(
        model.saveToServer()
      )
    });
    
    $q.all(savePromises).then(
      function success(results){...},
      function failed(results){...}
    );
    

    see the full API:

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

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

    0 讨论(0)
  • 2020-11-21 22:37

    If you're transpiling and have access to ES6, you can use spread syntax which specifically applies each iterable item of an object as a discrete argument, just the way $.when() needs it.

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

    MDN Link - Spread Syntax

    0 讨论(0)
  • 2020-11-21 22:39

    As a simple alternative, that does not require $.when.apply or an array, you can use the following pattern to generate a single promise for multiple parallel promises:

    promise = $.when(promise, anotherPromise);
    

    e.g.

    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>");
            });
        });
    });
    

    Notes:

    • I figured this one out after seeing someone chain promises sequentially, using promise = promise.then(newpromise)
    • The downside is it creates extra promise objects behind the scenes and any parameters passed at the end are not very useful (as they are nested inside additional objects). For what you want though it is short and simple.
    • The upside is it requires no array or array management.
    0 讨论(0)
  • 2020-11-21 22:46

    I want to propose other one with using $.each:

    1. We may to declare ajax function like:

      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. Part of code where we creating array of functions with ajax to send:

      var arrayOfFn = [];
      for (var i = 0; i < someDataArray.length; i++) {
          var ajaxFnForArray = new ajaxFn(someDataArray[i]);
          arrayOfFn.push(ajaxFnForArray);
      }
      
    3. And calling functions with sending ajax:

      $.when(
          $.each(arrayOfFn, function(index, value) {
              value.call()
          })
      ).then(function() {
              alert("Cheer!");
          }
      )
      
    0 讨论(0)
提交回复
热议问题