Reputation: 1838
I want to update data in the database after one or multiple files has been uploaded to Firebase Storage. I used the async
keyword on the complete function of the uploadTask and await
to push the new objects with the downloadURL to filesArr
.
However the result is not what I expected.
My usage of async/await didn't result in the expected behavior. The code inside Promise.all is executed before all the objects were pushed to filesArr. Can someone help me out?
onSubmitInvoiceData = () => {
const { files } = this.state;
if(files.length < 1) this.setState({ isLoading: false, errors: {...this.state.errors, general: ['Gelieve minstens één factuur te uploaden']} });
else {
const promises = [];
const filesArr = [];
files.forEach(file => {
const uploadTask = Storage.ref(`session-123/files/${file.name}`).put(file);
promises.push(uploadTask);
uploadTask.on('state_changed', snapshot => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
}, error => { console.log(error) }, async () => {
await uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => {
console.log('url: ', downloadURL);
filesArr.push({id: file.id, name: file.name, url: downloadURL});
});
});
});
Promise.all(promises).then(tasks => {
console.log('tasks: ', tasks);
Database.ref(`sessions/123`).update({
lastUpdate: Firebase.database.ServerValue.TIMESTAMP,
files: filesArr
}).then(() => this.setState({ isLoading: false }))
});
}
}
Upvotes: 0
Views: 2263
Reputation: 302
This may not be the actual answer but it may helps you to find out the way of achieving what you want:
onSubmitInvoiceData = () => {
const { files } = this.state;
if(files.length < 1) this.setState({ isLoading: false, errors: {...this.state.errors, general: ['Gelieve minstens één factuur te uploaden']} });
else {
const promises = [];
Promise.all(
files.map(file => {
return new Promise((resolve,reject)=>{
const uploadTask = Storage.ref(`session-123/files/${file.name}`).put(file);
promises.push(uploadTask);
uploadTask.on('state_changed', snapshot => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
}, error => { console.log(error) }, () => {
uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => {
console.log('url: ', downloadURL);
return resolve ({id: file.id, name: file.name, url: downloadURL});
});
});
})
})
).then(filesArr=>{
Promise.all(promises).then(tasks => {
console.log('tasks: ', tasks);
Database.ref(`sessions/123`).update({
lastUpdate: Firebase.database.ServerValue.TIMESTAMP,
files: filesArr
}).then(() => this.setState({ isLoading: false }))
});
})
}
}
I replaced your forEach
function with map
which can returns a promise. and put it inside a Promise.all
so after they all got their filesArr
, you will continue to next part.
The way you treated with async/await
in your code is not correct. while await
actually waiting for a promise to resolve, you have no Promise.resolve
, and you are using await
and .then()
together which i can't understand why!
check this:
let downloadURL = await uploadTask.snapshot.ref.getDownloadURL();
OR
uploadTask.snapshot.ref.getDownloadURL().then(downloadURL=>...)
I hope this can help you.
Upvotes: 1
Reputation: 6587
I think you will just need reduce with promise as follows
files.reduce((promiseChain, item, index) => {
return promiseChain.then(() => new Promise((resolve) => {
//here item is one of the items in files array.
this.myFunction(item, resolve);
}));
}, Promise.resolve()).then((tasks) => {
//tasks
});
Callback function which resolves current request.
myFunction(item, resolve) {
setTimeout(() => {
//do something with item, alongside send resolve when it is finished.
resolve(item);
}, 100);
}
Upvotes: 0