简体   繁体   中英

Javascript Loop doesn't wait for Firebase to complete uploading multiple files

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?

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!'); });

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);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM