I’m trying to build input to upload multiple files and get response from server to update a UI.
I built something like this using jQuery:
function UploadFile(file) {
return new Promise((resolve) => {
$.ajax({
url: "/api/admin/upload",
type: "POST",
data: file,
processData: false,
contentType: false,
success: function (data) {
var d = JSON.parse(data);
if (d.error_info) {
resolve({ r: "error", i: d.error_info });
} else if (d.success_info) {
resolve({ r: "success", i: "Ok" });
} else if (d.fileexists) {
resolve({ r: "fileexists", i: "Ok" });
} else {
resolve({ r: "error-0", i: data });
}
},
error: function (data) {
console.log(data);
resolve({ r: "error-0", i: "ajax error" });
},
});
});
}
$(document).on("change", "input", async function (e) {
e.preventDefault();
var files = $("input").prop("files");
$.each(files, function (k, file) {
//draw ui
});
$.each(files, async function (key, file) {
var formData = new FormData();
formData.append(`${key}`, file);
let FileNo = key + 1;
let TotalFiles = files.length;
var result = await UploadFile(formData);
console.log(result);
switch (result.r) {
case "success":
StatusIco.html(
'<i class="fa-solid fa-circle-check" data-info="Done"></i>'
);
break;
case "error":
StatusIco.html(
`<i class="fa-solid fa-circle-xmark" data-info="${result.i}"></i>`
);
break;
case "fileexists":
StatusIco.html(
'<i class="fa-solid fa-circle-exclamation" data-info="File exists"></i>'
);
break;
default:
console.log(result.i);
StatusIco.html(
'<i class="fa-solid fa-circle-xmark" data-info="Unknown error"></i>'
);
break;
}
//update total
let percentage = Math.round((100 * FileNo) / TotalFiles) + "%";
$(".uploading .percentage").html(percentage);
$(".uploading .head .text").html(`Uploaded ${FileNo} from ${TotalFiles}`);
//if last file
if (FileNo == TotalFiles) {
$(".uploading .head .text").html("Done");
}
});
});
Everything should work just fine, but sometimes number of total files + percentage wound get updated. Sometimes even my status icon will get stuck on uploading.
I need to upload them one by one because I have server file size limit and slow connection so if I upload more I’ll get 500 error or timed-out.
I tried to use promise.then but ended up with the same result.
Ty for help!
2
Answers
You can use jQuery Form Plugin to help you.
JQUERY
HTML
Your code does not upload the files one by one. Instead, it makes each http request for the files at once, and then each callback functions will return async (not in order). This happens because you’re using
$.each(<iterable>, <function>)
, which if youawait
inside the asynced function, it does not wait to finish until it calls the next iteration. See this jsfiddle, but also see thisSome suggestions:
.ajax
function to queue your requests. Keep in mind that client-side rate limiting is pointless if you don’t implement server-side rate limiting.asynchronous: false
on$.ajax
. see the docsPromise.all
does (it does not run the async tasks in order)