I intend to upload an array of files using jQuery.
This intention is wrapped in a function called uploadFilesUsingAjax()
;
var uploadFilesPromise = uploadFilesUsingAjax();
$.when(uploadFilesPromise).done(function (uploadFilesAjaxResult) {
// redirect to success page...
I need to wait for all the files to be uploaded successfully before doing something else.
Inside uploadFilesUsingAjax()
,
I wrote my code this way
function uploadFilesUsingAjax() {
var files = pages; // pages is a global variable which is an array of files
var url = "/users/" + currentUser.id + "/files.json";
var type = "POST";
console.info('files length:' + files.length);
if (files.length > 0) {
var promises=[];
for (var i = 0; i < files.length; i++) {
var data = new FormData();
var postData = {};
var file = files.getByIndex(i);
var key = i + 1;
if (typeof (file.id) !== "undefined" && file.id > 0) {
data.append(key, JSON.stringify(file));
} else {
data.append(key, file);
}
var request = $.ajax({
//this is the php file that processes the data
url: url,
//POST method is used
type: type,
//pass the data
data: data,
//Do not cache the page
cache: false,
xhr: function() {
// custom xhr
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload) { // check if upload property exists
myXhr.upload.addEventListener('progress',updatePagesProgress, false); // for handling the progress of the upload
}
return myXhr;
},
// DO NOT set the contentType and processData
// see http://stackoverflow.com/a/5976031/80353
contentType: false,
processData: false,
//success
success: function (json) {
// json is already an object thanks to cakephp code to serialize
//if POST is a success expect no errors
if (json.error == null && json.result != null) {
currentUser = json.result.User;
// error
} else {
alert(json.error);
}
}
});
promises.push( request);
}
var promise = promises[0];
for (var i = 1; i < promises.length; i++) {
promise = promise.then(promises[i]);
}
return promise.done(function () { console.log('all!')});
Unfortunately, I was not able to upload a lot of files before I got redirected to success page.
I have tried various StackOverflow solutions on how to do this. So far nothing works. Please advise.
Some code has been truncated to save space.
All your promises are parallel and not sequential.
A promise represents an already running task. Promises in JavaScript, unlike C# tasks or other abstractions are already started. The way to represent a task that has not started is a function returning a promise.
Since promises[i]
is already a promise - when you do promise.then(object)
it does not add a .then handler but rather return immediately. .then
ignores any arguments that are not a function.
This is why it returns early, it returns as soon as the first promise fulfills. You also don't need the .when
. Create a function that creates an upload process as such:
function createUploadTask(file,i){
return function(){
var data = new FormData();
var postData = {};
var file = files.getByIndex(i);
var key = i + 1;
if (typeof (file.id) !== "undefined" && file.id > 0) {
data.append(key, JSON.stringify(file));
} else {
data.append(key, file);
}
return $.ajax({...}); // return the promise
}
}
Now, you can map the files to tasks:
var tasks = files.map(createUploadTask);
Note, that now the tasks are each functions that return a promise over a file upload. They are not promises.
Now, you can chain them:
var p = tasks[0](); // start off the chain
for(var i = 1; i < tasks.length; i++){
// chain the next task, note, that we're passing a _function_ here
// when you return a promise from a `.then` it will fulfill when that promise
// fulfills, in our case the $.ajax
p = p.then(tasks[i]);
}
return p;
You also now don't need to use when, since you return a single promise. I assume you don't need the actual result here (but only to know success/failure).
You simply do:
function uploadFilesUsingAjax() {
// settings
if(tasks.length === 0){
// a method MUST always either return either synchronously or asynchronously never
// both, always return a promise. Otherwise you get API hell.
var d = $.Deferred();
d.reject(new Error("Called uploadFiles with no files to upload"));
return d.promise;
}
tasks = pages.map(createUploadTask)
var p = tasks[0](); // call first one
for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]);
return p;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With