我有一组Picture
个对象。我使用.map()
迭代它们,所以我可以将它们上传到我的firebase-storage。上传Picture
后,我想获取Picture
的网址并将其放入另一个数组中。
完成所有上传后,我有一个完整的网址数组,我希望db.push()
数据到我的数据库。
问题是{<1}}启动之前我的所有照片都已完成上传!
我如何让db.push()
等到db.push()
正确完成?
.map()
答案 0 :(得分:1)
这个问题有很多可能的方法。
您可以将上传功能放在setState
回调
this.setState({Arr : array}, () => {
// now the Upload of all Data should start
} )
使用承诺修改
let keysPromises = keys.map(
key =>
new Promise((resolve, reject) => {
const picture = pictures[key];
firebase
.storage()
.ref("images")
.child("artikelimgaes/" + userId)
.child("artikel/")
.child(titel)
.child(picture.name)
.put(picture)
.then(() => {
firebase
.storage()
.ref("images")
.child("artikelimgaes/" + userId)
.child("artikel/")
.child(titel)
.child(picture.name)
.getDownloadURL()
.then(url => {
const imgUrl = url;
array.push(url);
this.setState({ Arr: array }, resolve());
});
});
})
);
Promise.all(keysPromises).then(() => {
// now the Upload of all Data should start
});
答案 1 :(得分:1)
您正在对put()
和getDownloadURL()
执行多次调用,并且您希望等到所有这些调用都已处理完后再继续执行其他工作。
如果这些调用是 synchronous ,那就没问题了,就是执行会等到函数完成后再继续运行,但事实并非如此。
你可以说,因为它们都返回promise
,意味着它们是异步;因此,无需等待即可继续执行。
这就是问题所在。我们该如何解决?
这里的技巧是使用名为Promise.all()
的JS Promise的一个功能。这需要一系列承诺并返回自己的承诺。一旦承诺数组全部解决(或其中一个已被拒绝),则单个复合承诺将被解决或拒绝。
如果您使用的是现代JS,那么使用新的async
/ await
语法可以轻松实现这一点。
您将重新编写代码,使其看起来像这样:
警告:未经测试的代码
const getFirebase = pictureName =>
firebase
.storage()
.ref('images')
.child('artikelimgaes/' + this.props.user)
.child('artikel/')
.child(titel)
.child(pictureName)
const getImageUrls = async keys => {
const pictures = this.state.pictures[0]
const keys = Object.keys(pictures)
const picture = pictures[key]
await Promise.all(keys.map(key => getFirebase(picture.name).put(picture)))
await Promise.all(keys.map(key => getFirebase(picture.name).getDownloadURL(picture)))
}
const UploadForm = async event => {
event.preventDefault()
const db = firebase
.database()
.ref('app')
.child('cards')
//the stuff from the Form
const titel = this.titelInput.value
const grabtiefe = this.grapTiefeVonInput.value + ' - ' + this.grapTiefeBisInput.value
const transportbreite = this.transportbreiteVonInput.value + ' - ' + this.transportbreiteBisInput.value
const transporthoehe = this.transporthoeheVonInput.value + ' - ' + this.transporthoeheBisInput.value
const gewicht = this.GewichtdesArtikelsInput.value
const preis = this.priceInput.value
const desc = this.descInput.value
const adresse = this.props.address
const ort = this.props.ort
const mobil = this.props.mobil
const festnetz = this.props.festnetz
// get all the picture urls and save them to state.
this.setState({ Arr: await getImageUrls() })
// now the Upload of all Data should start
const coordinaten = this.state.cords
const images = this.state.Arr
const mainImage = this.state.Arr[0]
db.push({
grabtiefe: grabtiefe,
transportbreite: transportbreite,
transporthoehe: transporthoehe,
cardHeading: titel,
cardPreis: preis,
cardDesc: desc,
gewicht: gewicht,
address: adresse,
ort: ort,
gemietet: 0,
cords: coordinaten,
mobil: mobil,
festnetz: festnetz,
imageArr: images,
imageUrl: mainImage,
gebiet: this.state.gebiet,
bundesland: this.state.bundesland,
uid: this.props.user
})
this.setState({
redirect: true
})
}
使用getImageUrls
功能,我将您的单map
拆分为两个。第一个map
负责将所有图片放入firebase
。每个put都返回一个承诺,map
作为一组承诺返回。然后这个数组被await
编辑,即代码执行等待直到所有的promise都被解析。我们现在可以通过调用getDownloadURL()
来执行相同的操作。
请注意,如果要在函数中使用await
关键字,则必须将该函数标记为async
。您可以在getImageUrls
函数中看到这种情况。
当函数标有async
时,无论函数内部发生了什么,它都将始终返回一个promise。此隐式承诺仅在函数完成时自动解析,在这种情况下,两个阵列中的所有承诺都已解析。它等待,因为我们正在等待对Promise.all()
所以现在我们需要确保async
getImageUrls()
函数返回的单个隐式承诺已经解决,然后继续我们的其他工作。所以我们也需要await
这个承诺,这意味着我们需要将UploadForm`函数标记为异步以允许这样做。
最终结果应该是从getImageUrls()函数返回的一个很好的pictureUrls数组。现在,您可以使用此数组在继续执行数据库工作之前设置状态,并且知道所有图片都已安全地存储在firebase中。