Programmatically creating a chained sequence of jQuery promises

前端 未结 2 662
我寻月下人不归
我寻月下人不归 2021-01-01 08:35

I have a function to delete a list an array of files, filePaths, by calling a single deleteFile(filePath) on each of the files in a list (some APIS I\'m using don\'t support

相关标签:
2条回答
  • 2021-01-01 09:05

    $.when doesn't launch anything, they were launched in your map loop. $.when simply returns a promise for an array of promises.

    If you want them sequentially, use reduce:

    function deleteFiles(filePaths) {
        return filePaths.reduce(function(cur, next) {
             return cur.then(function() {
                 return deleteFile(next);
             });
        }, $().promise());
    }
    

    If you want them sequentially, while also getting the array back with respective results:

    function deleteFiles(filePaths) {
        var ret = filePaths.slice(0);
        return filePaths.reduce(function(cur, next, i) {
             return cur.then(function() {
                 return ret[i] = deleteFile(next);
             });
        }, $().promise()).then(function(){
             return $.when.apply($, ret);
        })
        //These don't make any sense to call in this function but sure
        .then(function(schemas) {
             console.log("DONE", this, schemas);
        }).fail(function(error) {
             console.log("My ajax failed");
        });
    }
    
    0 讨论(0)
  • 2021-01-01 09:09

    this isn't what $.when does, does it? it seems to launch them all at once

    New updated answer: I have just found out that for new versions of jQuery (>1.8), we can chain jQuery promises simply using $.then. In your case, you could try:

    function deleteFiles(filePaths){
        var d = jQuery.Deferred(), 
        for (var i=0;i<filePaths.length;i++){
            d.then(deleteFile(filePath[i]));
        }
    
        d.resolve();
    }
    

    You could take a look at my similar answer at jQuery Deferred and Promise for sequential execution of synchronous and asynchronous funcitons

    Old answer:

    As I understand, you need to handle the returned value one-by-one, I think that you don't need to care about the orders of executing callbacks as the next deleteFile does not depend on the previous one's result. If that's the case, just try this:

     function deleteFiles(filePaths){
            $.each(filePaths,function(index,val){
                  deleteFile(val)
                    .done(function(schema){
    
                    })
                    .fail(function(error){
    
                    });
            });
       }
    

    Another way to write this if you need to return deferreds:

    function deleteFiles(filePaths)
        return $.map(fileKeys, function (val,index) {
            return deleteFile(val);
        });
    }
    
    $.each(deleteFiles(yourfilePaths),function(index,val){
        val
        .done(function(schema){
        })
        .fail(function(error){
        });
    });
    

    If you do need to chain them, I think you can create a recursive function like this:

    function deleteFiles(filePaths, currentIndex){
        if (filePath.length < currentIndex + 1){ //Stop condition.
            return;
        }
    
        var promise = deleteFile(filePath[currentIndex]);
        if (promise){
            promise
             .done(function(schema){
                //do your job with returned value, decide whether to call the next path in the chain
                deleteFiles(filePaths,currentIndex++);
             })
             .fail(function(error){
                  //I assume that you don't call the next path if the current one returns error.
             });
        }
    }
    
    0 讨论(0)
提交回复
热议问题