【问题标题】:Call a method once all deferred completes?所有延迟完成后调用方法?
【发布时间】:2014-06-16 13:38:13
【问题描述】:

我有这门课:

(function(){
"use strict";

var FileRead = function() {
    this.init();
};


p.read = function(file) {

    var fileReader = new FileReader();
    var deferred = $.Deferred();

    fileReader.onload = function(event) {
        deferred.resolve(event.target.result);
    };

    fileReader.onerror = function() {
        deferred.reject(this);
    };

    fileReader.readAsDataURL(file);

    return deferred.promise();

};

lx.FileRead = FileRead;
}(window));

类被循环调用:

var self = this;
    $.each(files, function(index, file){
        self.fileRead.read(file).done(function(fileB64){self.fileShow(file, fileB64, fileTemplate);});

    });

我的问题是,有没有办法在循环完成并且self.fileRead 返回后调用一个方法,它会延迟循环中的所有内容?

即使一个或多个延迟失败,我也希望它调用该方法。

【问题讨论】:

  • 这不是.always() 的用途吗?
  • 你应该使用更好的 promise 库。
  • .read 是否在对象内部使用任何方法?有什么理由它是一个实例方法吗?

标签: javascript jquery promise jquery-deferred


【解决方案1】:

$.when 可让您将多个 Promise 封装为一个。其他 Promise 库也有类似的东西。构建一个由 fileRead.read 返回的 Promise 数组,然后将该数组传递给 $.when 并将 then/done/fail/always 方法连接到由 .when 返回的 Promise

    // use map instead of each and put that inside a $.when call
    $.when.apply(null, $.map(files, function(index, file){
        // return the resulting promise
        return self.fileRead.read(file).done(function(fileB64){self.fileShow(file, fileB64, fileTemplate);});

    }).done(function() {  

      //now everything is done 
    })

【讨论】:

  • 文档中有示例,现在您知道要使用的 api 的名称api.jquery.com/jquery.when
  • @BenjaminGruenbaum - 同意。我在下面的答案中进一步评论了
  • 为什么这个答案没有满足要求时被接受,“即使一个或多个延迟失败也要调用方法。”?
【解决方案2】:
var self = this;
var processFiles = function (data) {
    var promises = [];
    $.each(files, function (index, file) {
        var def = data.fileRead.read(file);
        promises.push(def);
    });
    return $.when.apply(undefined, promises).promise();
}

self.processFiles(self).done(function(results){ 
    //do stuff
});

$.when 说“当所有这些承诺都得到解决时……做点什么”。它需要无限(可变)数量的参数。在这种情况下,你有一个 promises 数组;

【讨论】:

    【解决方案3】:

    我知道这已关闭,但正如$.when 的文档所述:在多个延迟的情况下,其中一个延迟被拒绝,jQuery.when 立即为其主延迟触发 failCallbacks . (重点是我的)

    如果你想在一个失败的情况下完成所有延迟,我相信你需要按照下面的这些思路提出你自己的插件。 $.whenComplete 函数需要一个返回 JQueryPromise函数 数组。

        var whenComplete = function (promiseFns) {
            var me = this;
            return $.Deferred(function (dfd) {
                if (promiseFns.length === 0) {
                    dfd.resolve([]);
                } else {
                    var numPromises = promiseFns.length;
                    var failed = false;
                    var args;
                    var resolves = [];
    
                    promiseFns.forEach(function (promiseFn) {
                        try  {
                            promiseFn().fail(function () {
                                failed = true;
                                args = arguments;
                            }).done(function () {
                                resolves.push(arguments);
                            }).always(function () {
                                if (--numPromises === 0) {
                                    if (failed) {
                                        //Reject with the last error
                                        dfd.reject.apply(me, args);
                                    } else {
                                        dfd.resolve(resolves);
                                    }
                                }
                            });
                        } catch (e) {
                            var msg = 'Unexpected error processing promise. ' + e.message;
                            console.error('APP> ' + msg, promiseFn);
                            dfd.reject.call(me, msg, promiseFn);
                        }
                    });
                }
            }).promise();
        };
    

    【讨论】:

      【解决方案4】:

      为了满足要求,“即使一个或多个延迟失败也要调用该方法”,理想情况下您需要一个 .allSettled() 方法,但 jQuery 没有那种特殊的糖,所以您必须自己动手工作:

      您可以找到/编写一个$.allSettled() 实用程序或通过.when().then() 的组合达到相同的效果,如下所示:

      var self = this;
      $.when.apply(null, $.map(files, function(index, file) {
          return self.fileRead.read(file).then(function(fileB64) {
              self.fileShow(file, fileB64, fileTemplate);
              return fileB64;//or similar
          }, function() {
              return $.when();//or similar
          });
      })).done(myMethod);
      

      如果它存在,$.allSettled() 会在内部做类似的事情。

      接下来,“在myMethod中,如何区分好的响应和错误?”,但这是另一个问题:)

      【讨论】:

        猜你喜欢
        • 2014-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-17
        相关资源
        最近更新 更多