Зацикливание через jQuery Отложенные после того, как все promises были вызваны

В настоящее время я пытаюсь создать загрузчик файлов с помощью файла HTML5 FileAPI. Файл Uploader должен обрабатывать несколько файлов и показывать предварительный просмотр изображений, если файл является изображением.

так как класс FileReader работает асинхронно, я хочу подождать, пока все файлы не будут прочитаны. Поэтому я использую Deferreds.

Метод, который читает файл, возвращает обещание. Другой метод обрабатывает все файлы и выталкивает все promises в массив. Затем я применяю метод then(), как только все promises были добавлены в мой массив.

Теперь к моей проблеме. Поскольку метод then() вызывается только один раз, когда я получил все promises. У меня нет возможности обработать каждое обещание. Я хочу сделать, чтобы пропустить все мои promises, когда они все там, и вернет результат.

Это мой 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 Object 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]);
        }
    });

},

Использую ли я неправильный подход для отсрочек и promises? Разве они не должны использоваться так, как я пытаюсь сделать, и есть ли более элегантный способ достичь моей цели?

Ответ 1

Использую ли я неправильный подход для отсрочек и promises?

Да. При асинхронном обратном вызове вы не должны обращаться к promises, а только к аргументам обратного вызова. Возвратное обещание $.when разрешает с массивом параметров .resolve() для каждого из promises в массиве - вы можете петля над объектом arguments для доступа к результатам:

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

Ответ 2

вы можете использовать объект аргументов для ссылки на все значения, возвращаемые объектами обещания

$.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);
    }
});

Ответ 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]);
        });
    });
},

Конечно, это снова усложнится, когда вы обработаете обработку результатов, но это должно дать вам краткую основу.