在调用所有Promise后循环遍历 jQuery Deferreds

IT技术 javascript jquery jquery-deferred deferred
2021-03-02 21:41:22

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

由于 FileReader 类异步工作,我想等到所有文件都被读取。因此我正在使用延迟。

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

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

这是我的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();
},

这里来的文件管理器是应该调用FileProcessor.read()方法对象的handleFileSelect()方法。

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

},

我是否对延迟和Promise使用了错误的方法?难道它们不应该像我试图做的那样使用,有没有更优雅的方式来实现我的目的?

3个回答

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

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

$.when.apply($, promises).then(function () {
    for (var i = 0; i < arguments.length; i++) {
        var singleresult = arguments[i][0];
        console.log(singleresult);
    }
});
谢谢!那么之后循环遍历我的Promise是完全可以的吗?
2021-04-19 21:41:22
不是通过promises(无论如何这并没有多大帮助 - 它们只是您无法直接访问其值的Promise),而是通过您的回调参数 - 这是每个Promise的结果。
2021-05-11 21:41:22

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

$.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);
    }
});
@ThomasDavidPlat 没有问题:)
2021-05-03 21:41:22
谢谢!那个答案有帮助。我希望你在我接受@Bergi 的回答时不会因为进一步的解释而生气
2021-05-13 21:41:22

我看到你已经接受了一个答案,但你可能想知道你的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]);
        });
    });
},

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

可以做,但对我来说,我们已经撞上了可读性墙。
2021-05-05 21:41:22
为什么不进一步简化为$.when.apply($, $.map(e.target.files, FileProcessor.read)).then(…):-)
2021-05-11 21:41:22