【问题标题】:Looping through jQuery Deferreds after all promises have been called在调用所有承诺后循环通过 jQuery Deferreds
【发布时间】:2014-02-18 00:13:51
【问题描述】:

我目前正在尝试使用 HTML5 FileAPI 构建文件上传器。文件上传器应该处理多个文件并在文件是图像时显示图像预览。

因为 FileReader 类是异步工作的,所以我想等到所有文件都被读取。因此,我使用的是 Deferreds。

读取文件的方法正在返回一个承诺。另一种方法循环遍历所有文件并将所有 Promise 推送到一个数组中。然后,一旦所有承诺都添加到我的数组中,我就会应用 then() 方法。

现在我的问题。由于 then() 方法只被调用一次,当我得到所有的承诺时。我没有机会处理每一个承诺。我想要做的是,一旦我所有的承诺都在那里循环并返回结果。

这是我的 FileProcessor 对象

read: function(file) {
    var reader = new FileReader();
    var deferred = $.Deferred();

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

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

    if(/^image/.test(file.type))
        reader.readAsDataURL(file);

    return deferred.promise();
},

FileManager 对象的 handleFileSelect() 方法来了,它应该调用 FileProcessor.read() 方法。

handleFileSelect: function(e){
    var $fileList = $('#file-list');

    var files = e.target.files;
    var promises = []; //Promises are going to be stored here
    var filestring = '';

    var processedFile;

    // Loop trough all selected files
    for(var i = 0; i < files.length; i++){
        // Store the promise in a var...
        processedFile = FileProcessor.read(files[i]);   
        // And push it into the array where the promises are stored
        promises.push(processedFile);                   
    }

    // Once all deferreds have been fired...
    $.when.apply(window, promises).then(function(){
        for(var i = 0; i < promises.length; i++){
            // PROBLEM HERE: I need to get the 
            // result from my resolved Deferred
                            // of every single promise object
            console.log(promises[i]);
        }
    });

},

我是否对延迟和承诺使用了错误的方法?它们不应该像我想要做的那样被使用吗?有没有更优雅的方式来实现我的目的?

【问题讨论】:

    标签: javascript jquery jquery-deferred deferred


    【解决方案1】:

    我是否对延迟和承诺使用了错误的方法?

    是的。在异步回调中,您不应访问promises,而只能访问回调参数。 $.when 的返回承诺确实使用数组中每个承诺的 .resolve() 参数数组解析 - 您可以遍历 arguments object 以访问结果:

    $.when.apply($, promises).then(function () {
        for (var i = 0; i < arguments.length; i++) {
            var singleresult = arguments[i][0];
            console.log(singleresult);
        }
    });
    

    【讨论】:

    • 谢谢!所以之后循环通过我的承诺完全可以吗?
    • 不是通过promises (无论如何这并没有多大帮助-它们只是您无法直接访问其值的承诺),而是通过回调的参数-这是每个参数的结果承诺。
    【解决方案2】:

    您可以使用arguments object 来引用承诺对象返回的所有值

    $.when.apply($, promises).then(function () {
        for (var i = 0; i < arguments.length; i++) {
            var data = arguments[i][0];
            // PROBLEM HERE: I need to get the 
            // result from my resolved Deferred
            // of every single promise object
            console.log(data);
        }
    });
    

    【讨论】:

    • 谢谢!这个答案有帮助。由于进一步的解释,我希望当我接受@Bergi 的回答时你不会生气
    • @ThomasDavidPlat 没有问题 :)
    【解决方案3】:

    我看到你已经接受了一个答案,但你可能想知道你的 handleFileSelect 方法可以显着简化如下

    handleFileSelect: function(e) {
        var promises = $.map(e.target.files, function(file) {
            return FileProcessor.read(file);
        });
        $.when.apply(window, promises).then(function() {
            $.each(arguments, function(i, a) {
                console.log(a[0]);
            });
        });
    },
    

    当然,当你充实结果处理时它会再次变得更加复杂,但这应该会给你一个很好的简洁基础。

    【讨论】:

    • 为什么不进一步简化为$.when.apply($, $.map(e.target.files, FileProcessor.read)).then(…)? :-)
    • 可以,但对我来说,我们已经达到了可读性的门槛。
    猜你喜欢
    • 2019-06-17
    • 1970-01-01
    • 2020-08-16
    • 2016-09-09
    • 2017-12-04
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多