【问题标题】:how to know when several callbacks have been successfully executed with no returned promises如何知道几个回调何时成功执行而没有返回的承诺
【发布时间】:2014-08-20 15:11:14
【问题描述】:

!!!这个问题不是关于如何将一组承诺传递给when 函数,因为file 方法和onload 都没有返回承诺,它不是重复的

我有一个自定义方法执行不返回承诺的异步函数。我的自定义方法确实返回了一个承诺。实现该功能的正确方法是什么 - 使用示例 1 中的超时或检查回调函数中的相等性(例如示例 2)?
EXAMPLE1:

getAllFiles: function () {
    var def = $.Deferred();
    var files = [];
    fileEntries.forEach(function(fileEntry){
        fileEntry.file(function (file) {
            var reader = new FileReader();
            reader.onload = function (e) {
                files.push({
                    name: fileEntry.fullPath,
                    content: e.target.result
                });
            };
            reader.readAsArrayBuffer(file);
        });
    });

    //this resolves the deffered    
    var interval = setInterval(function(){
       if (files.length === fileEntries.length) {
           def.resolve(files);
           clearInterval(interval);
       }
    }, 1000);

    return def.promise();
}

示例 2

getAllFiles: function () {
    var def = $.Deferred();
    var files = [];
    fileEntries.forEach(function(fileEntry){
        fileEntry.file(function (file) {
            var reader = new FileReader();
            reader.onload = function (e) {
                files.push({
                    name: fileEntry.fullPath,
                    content: e.target.result
                });
                //this resolves the deffered
                if (files.length === fileEntries.length) {
                   def.resolve(files);
                   clearInterval(interval);
                }
            };
            reader.readAsArrayBuffer(file);
        });
    });

    return def.promise();
}

【问题讨论】:

  • 看起来您正在使用 jQuery,这意味着您可以利用 $.when
  • @zzzzBov,我不明白在这里如何使用 jQuery。各位大神能否举个具体的例子来说明我的情况?对于用户when 异步方法应该返回承诺,但file 方法和onload 都不返回承诺。
  • 您的第二个示例不正确,因为您不止一次地解决了延迟问题(实际上是在每个循环迭代中)。根据您的要求,计时器可能不够可靠。您是否尝试过维护一个计数器,并且仅在读取最后一个文件时才解决延迟问题?

标签: javascript


【解决方案1】:

然后为每个异步函数(onload 处理程序)创建一个承诺!

getAllFiles: function () {
    var deferreds = fileEntries.map(function(fileEntry){
        var def = $.Deferred();
        fileEntry.file(function (file) {
            var reader = new FileReader();
            reader.onload = function (e) {
                def.resolve({
                    name: fileEntry.fullPath,
                    content: e.target.result
                });
            };
            reader.onerror = def.reject; // don't forget error handling!
            reader.readAsArrayBuffer(file);
        }, def.reject); // here as well
        return def;
    });
    return $.when.apply($, deferreds).then(function() {
        var files = $.map(arguments, function(args) { return args[0]; });
        return files;
    });
}

mapping then 中的参数是必要的,因为jQuery's $.when result is so ugly

回答您的实际问题:

实现该功能的正确方法是什么 - 使用示例 1 中的超时或检查回调函数中的相等性(例如示例 2)?

从回调中执行。使用setInterval 的轮询结果被鄙视(它更慢,不会捕获错误,甚至在错误情况下泄漏)。

【讨论】:

  • 感谢您花时间回复,它让我对 Jquery 的延迟有了新的认识 :)。不过有一个问题,为什么你从file 回调返回def 而不是def.promise()
  • 你也可以。 Deferred 实现了when 使用的Promise 接口,在其上调用.promise() 只会构造另一个对象。
  • 谢谢。但是def 可以在外部为getAllFiles 函数解析,对吗?如果我们返回Promise,我们会阻止它。我也不明白为什么我需要这个var files = $.map(arguments, function(args) { return args[0]; });,因为参数已经包含一个对象数组。?我可以通过return Array.prototype.slice.call(arguments); 简单地将它变成真正的数组
  • 奇怪的是,当我调用 getAllFiles().done(function (files) { }); 这样的方法时,files 变量只包含第一个对象,而不是 then 返回的数组。任何想法为什么会发生这种情况?
  • 不,def 不能在getAllFiles 之外解析,因为我们不返回def,而是通过$.when 构造的promise。这就是为什么在这里使用 deferred 是省钱的。如果您将读取单个文件条目放在单独的函数中,那么您确实应该使用.promise()。这里也可能更干净,如果不仅仅是为了减少混乱:-)
猜你喜欢
  • 2023-04-03
  • 2020-07-11
  • 2021-01-13
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 2020-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多