在继续之前,我如何等待异步调用的.map()完成?

时间:2018-01-18 15:14:22

标签: javascript reactjs function firebase ecmascript-6

我有一组Picture个对象。我使用.map()迭代它们,所以我可以将它们上传到我的firebase-storage。上传Picture后,我想获取Picture的网址并将其放入另一个数组中。

完成所有上传后,我有一个完整的网址数组,我希望db.push()数据到我的数据库。

问题是{<1}}启动之前我的所有照片都已完成上传!

我如何让db.push()等到db.push()正确完成?

.map()

2 个答案:

答案 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中。