views:

22

answers:

2

I want to implement sequential upload of files (with XMLHttpRequest level2) to server. Got bunch of DOM elements with File attached (FileAPI - W3C draft). I want to upload in sequence (one after another), but XMLHttpRequest works asynchronously. Little code sample:

$thumbnails = $('queue').find('.item');
for (var i = 0, len = thumbnails.length; i < len; i++) {
  var xhr = new XMLHttpRequest();
  xhr.upload.onload = function(ev){}; // fires on upload complete
  var fd = new FormData
  fd.append('Files['+i+']', $thumbnails[i].file) // insert atached File to FormData

  xhr.open("POST", 'server_url', true) // last true means "use asynch rq"
  xhr.send(fd)
}

Problem with this code is, that FOR cycle iterates independently on upload proces of file. So more paralel uploads are started:

  • iteration starts,
    • xhr is created/populated,
    • upload begins,
    • new iteration

This design create new xhr object even if previous upload is not finished. But I still want to hold asynch paradigm (no browser block, progress events, etc.) of upload. Just cannot figure out, how to wait for current upload to finish and then start new upload cycle.

Any ideas?

A: 

You can create a stack and handle the requests recursively, also reusing the same request object.

I know, it rocks! :) Here is your code:

// last in, first out.
var stack = [];

$('queue').find('.item').each(function(i, el){
    // insert atached File to FormData
    var fd = new FormData();
    fd.append('Files['+i+']', el.file);
    stack.push(fd);
});

var xhr = new XMLHttpRequest();

(function recur() {

  // fires on upload complete
  xhr.upload.onload = function(ev) {
    // do recursion until the stack is not empty
    if (stack.length) recur();
  };

  // send an asynchronous POST request
  xhr.open("POST", 'server_url', true);
  xhr.send(stack.shift());

})();
galambalazs
I think this will be solution. Thank you sooooooooooooo much.
srigi
@srigi np man, stay cool, stay sharp :)
galambalazs
A: 

I have a useful javascript library for this sort of thing: http://caolanmcmahon.com/async.html

You could easily rewrite this code to use forEachSeries or mapSeries... along the lines of:

async.forEachSeries(thumbnails, function(thumb, callback){
    var xhr = new XMLHttpRequest();
    xhr.upload.onload = function(ev){ callback(); };
    ...
});
Caolan