Programmatically creating a chained sequence of jQ

2019-01-23 21: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 bulk delete). The function deleteFile return a jQuery promise and resolves/rejects upon deleting the file.

function deleteFiles(filePaths)
    var deferreds = $.map(fileKeys, function (val, index) {
        return deleteFile(filePath);
    });

    $.when.apply($, deferreds).then(function (schemas) {
        console.log("DONE", this, schemas);
        deferred.resolve();
    }, function (error) {
        console.log("My ajax failed");
        deferred.reject(error);
    });

I am getting .reject calls on some of the files in the list (and I know they exist), so I'm thinking I might need to turn the array of filePaths into a chaining of calls, like a queue (b/c this isn't what $.when does, does it? it seems to launch them all at once). I have know idea how to do this (like .deleteFile(path1).deletePath(path2). etc when they are in an array like this.

Any help is appreciated in advance.

2条回答
爷、活的狠高调
2楼-- · 2019-01-23 22:11

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.
         });
    }
}
查看更多
唯我独甜
3楼-- · 2019-01-23 22:26

$.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");
    });
}
查看更多
登录 后发表回答