2

I would like to chain an asynchronous ajax function that is called several times within a loop. Why? Because that function is to upload files but I want it to serially upload files rather than uploading all of them at once. I don't want to use async false because I want the progress updated on the DOM.

for (var i = 0; i < files.length; i++) {
         var fd = new FormData();

         fd.append('file', files[i]);
         fd.append('galleryid', galleryid);

        sendFileToServer(fd); //chain this function call
    }

function sendFileToServer(formData)
{
    var uploadURL ="includes/ajax/images/uploadImagePage.php"; //Upload URL
    var extraData ={}; //Extra Data.
    return jqXHR=$.ajax({
            xhr: function() {
            var xhrobj = $.ajaxSettings.xhr();
            if (xhrobj.upload) {
                    xhrobj.upload.addEventListener('progress', function(event) {
                        var percent = 0;
                        var position = event.loaded || event.position;
                        var total = event.total;
                        if (event.lengthComputable) {
                            percent = Math.ceil(position / total * 100);
                        }
                        //Set progress
                       $('#uploadImageResponse').html(percent+'%');
                    }, false);
                }
            return xhrobj;
        },
    url: uploadURL,
    type: "POST",
    async:true,
    contentType:false,
    processData: false,
        cache: false,
        data: formData,
        success: function(data){
            status.setProgress('Upload completed. 100%.');

        }
    }); 


}

I don't understand how jquery deferred objects work.

2
  • Why do you want to upload them in a single request? It makes far more sense for both client and server side code. Commented May 18, 2015 at 7:05
  • 3
    why don't you use callback? Commented May 18, 2015 at 7:06

2 Answers 2

2

There are a number of different approaches for serializing multiple requests like this. Here's one way that uses a manual iteration instead of the for loop so you only advance to the next iteration when the previous one has completed.

Manual Iteration

function sendAllFiles(files) {
    var index = 0;

    function next() {
        var fd;
        if (index < files.length) {
            fd = new FormData();
            fd.append('file', files[index]);
            fd.append('galleryid', galleryid);
            ++index;
            // send this file and when done, do the next iteration
            sendFileToServer(fd).then(next);
        } else {
            // all files are done now
        }
    }
    // start the first iteration
    next();
}

Chained promises using .reduce()

And, here's a different design pattern using .reduce() and chained promises:

files.reduce(function(p, item) {
    return p.then(function() {
        var fd = new FormData();
        fd.append('file', item);
        fd.append('galleryid', galleryid);
        return sendFileToServer(fd);
    });
}, $.Deferred().resolve()).then(function() {
    // all files are done now
});
Sign up to request clarification or add additional context in comments.

1 Comment

jfriend00: The manual iteration worked best for me. Very easy to implement. Thanks a million!!!
0

You could always try this...

function step1() { 
       updatePercentage(); 
       $.ajax({ ... , // fill in these details
                  success: step2 }); }
function step2(data) { 
      updatePercentage(); 
       $.ajax({ ... ,
                success: step3 });
}
function step3(data) { 
       updatePercentage(); 
       $.ajax({ ... ,
                success: step4?? });
}

This could be refactored down. I'll leave that for you though :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.