我想在将一个或多个文件上传到Firebase Storage之后更新数据库中的数据。我在上载任务的完整功能上使用了async
关键字,并使用了await
将带有downloadURL的新对象推送到了filesArr
。
但是结果不是我期望的。
我对async / await的使用未导致预期的行为。 Promise.all中的代码在将所有对象推送到filesArr之前执行。有人可以帮我吗?
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 }))
});
}
}
答案 0 :(得分:1)
这可能不是实际答案,但可以帮助您找到实现所需目标的方法:
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 }))
});
})
}
}
我用forEach
替换了您的map
函数,该函数可以返回承诺。并将其放在Promise.all
中,这样在他们都拿到filesArr
之后,您将继续进行下一部分。
您在代码中使用async/await
的方式是不正确的。 await
实际上正在等待承诺的解决,而您没有Promise.resolve
,并且您正在同时使用await
和.then()
,我不知道为什么!
检查一下:
let downloadURL = await uploadTask.snapshot.ref.getDownloadURL();
要么
uploadTask.snapshot.ref.getDownloadURL().then(downloadURL=>...)
希望这对您有所帮助。
答案 1 :(得分:0)
我认为您只需要按如下承诺减少
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
});
解决当前请求的回调函数。
myFunction(item, resolve) {
setTimeout(() => {
//do something with item, alongside send resolve when it is finished.
resolve(item);
}, 100);
}