Max Koretskyi
Max Koretskyi

Reputation: 105449

How to know when several callbacks have been successfully executed with no returned promises

I have a custom method that executes async functions which DO NOT return promises. My custom method does return a promise. What is the correct way to implement the functionality - using timeout like in example 1 or checking for equality in the callback function like in example 2?

EXAMPLE 1:

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

EXAMPLE 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();
}

Response to potential duplicate

This question is not about how to pass an array of promises to the when function since neither file method nor onload return promises.

Upvotes: 0

Views: 123

Answers (1)

Bergi
Bergi

Reputation: 664297

Simply make a promise for each async function (onload handler) then!

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

(the mapping over the arguments in the then is necessary because jQuery's $.when result is so ugly)

To answer your actual question:

What is the correct way to implement the functionality - using timeout like in example 1 or checking for equality in the callback function like in example 2?

Do it from the callback. Polling results with setInterval is despised (it's slower, won't catch errors and even leak in the error case).

Upvotes: 1

Related Questions