问题
I'm trying to upload multiple files and then execute some code after all the files are uploaded but my loop doesn't wait until each upload completes.
Iterating files:
//files is an array of local files from a <input type="file">
for (var i = 0, f; f = files[i]; i++) {
var imageFile = files[i];
var response = uploadImageAsPromise(imageFile);
}
//after completing all uploads, execute some code here
console.log("Finished uploading all files");
Upload function:
function uploadImageAsPromise(imageFile) {
var image_id = new Date().valueOf();
var storageRef = firebase.storage().ref().child(image_id + "");
return new Promise(function (resolve, reject) {
//Upload file
var task = storageRef.put(imageFile);
//Update progress bar
task.on('state_changed',
function progress(snapshot) {
var percentage = snapshot.bytesTransferred / snapshot.totalBytes * 100;
},
function error(err) {
console.log(err);
},
function complete() {
task.snapshot.ref.getDownloadURL().then(function (downloadURL) {
var picture = downloadURL;
console.log("Finished uploading file: " + image_id);
});
}
);
});
}
However, my 1st console log gets executed even before all files are uploaded. How do I made it wait until everything is done?
回答1:
The first problem is your uploadImageAsPromise
function. It never actually resolves the promise it creates, so anything that is waiting on the result will wait forever.
This should presumably work:
function uploadImageAsPromise(imageFile) {
var image_id = new Date().valueOf();
var storageRef = firebase.storage().ref().child(image_id + "");
return new Promise(function (resolve, reject) {
//Upload file
var task = storageRef.put(imageFile);
//Update progress bar
task.on('state_changed',
function progress(snapshot) { },
function error(err) { reject(err); },
function complete() { resolve(task); }
);
}).then(function (task) {
return task.snapshot.ref.getDownloadURL();
}).then(function (downloadURL) {
console.log("Finished uploading file: " + image_id);
return downloadURL;
});
}
You're not doing anything to wait until the promises complete, so naturally, the next code will continue executing.
To upload the files in parallel and wait until they're done
With async/await (if your execution environment supports it):
async function uploadFiles(files) {
await Promise.all(files.map(uploadImageAsPromise));
}
async function someOuterFunction(files) {
await uploadFiles(files);
console.log('All done!');
}
someOuterFunction(files);
Without async/await:
Promise.all(files.map(uploadImageAsPromise))
.then(function () {
console.log('All done!');
});
To upload the files sequentially and wait until they're done
With async/await (if your execution environment supports it):
async function uploadFiles(files) {
for (let file of files) {
await uploadImageAsPromise(file);
}
}
async someOuterFunction(files) {
await uploadFiles(files);
console.log('All done!');
}
someOuterFunction(files);
Without async/await:
files
.reduce(function (acc, file) {
return acc.then(function () { return uploadImageAsPromise(file); });
}, Promise.resolve())
.then(function () { console.log('All done!'); });
回答2:
You need to wait for all of the promises to resolve. You can do this concurrently using Promise.all
(docs here).
var promises = [];
for (var i = 0, f; f = files[i]; i++) {
var imageFile = files[i];
promises.push(uploadImageAsPromise(imageFile));
}
Promise.all(promises).then(function(values) {
//after completing all uploads, execute some code here
console.log("Finished uploading all files", values);
}).catch(function(error) {
console.log("One of the promises rejected.", error);
});
来源:https://stackoverflow.com/questions/53809980/javascript-loop-doesnt-wait-for-firebase-to-complete-uploading-multiple-files