如何在array.map方法中等待承诺解决?

时间:2019-10-31 08:07:33

标签: javascript reactjs asynchronous promise

我想将照片上传到Firebase存储。

在React组件的状态下,我有带有照片的数组。照片是用户通过文件输入浏览的文件。如果文件需要上传到存储空间,则照片的属性为.needUploadtrue

这是上传功能:

uploadPhotos = () => {
    let photosToSave = []
    if (this.state.photos.length) {
      photosToSave = this.state.photos
        .filter(photo => photo.needUpload && true)
        .map(photo => {
          const extensionPattern = /(?:\.([^.]+))?$/
          const fileName = photo.value.name
          const fileExtension = extensionPattern.exec(fileName)[1]
          const newFileName = new Date().getTime()
          const fileLocation = storageRef.child('estateObjects/' + newFileName + '.' + fileExtension)

          return new Promise(resolve => {
            fileLocation.put(photo.value).on(
              firebase.storage.TaskEvent.STATE_CHANGED,
              snapshot => {
                //let progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
              },
              null,
              () => {
                fileLocation.getDownloadURL().then(url => {
                  resolve({ url: url, file: newFileName + '.' + fileExtension })
                })
              }
            )
          })
        })
      return Promise.all(photosToSave).then(response => {
        return response
      })
    } else return Promise.all(photosToSave).then(response => [])
  }

主要问题是,当上传开始时,它(耐心地)等待,我想先上传2-3个文件,然后在“解析”数组中,我得到重复的数组元素。所以有些事情做错了,但是我不明白是什么...

也许是新文件名的问题??当文件重命名为新的Date.getTime()会为几个文件同时返回时,会导致它们同时上传吗?

enter image description here

3 个答案:

答案 0 :(得分:1)

map循环运行非常快,因此两次迭代之间的时间不会改变

因此,我建议您使用index来确保文件名唯一性

uploadPhotos = () => {
  let photosToSave = [];

  if (this.state.photos.length) {
    photosToSave = this.state.photos.filter(photo => photo.needUpload && true).map((photo, index) => {
      const extensionPattern = /(?:\.([^.]+))?$/;
      const fileName = photo.value.name;
      const fileExtension = extensionPattern.exec(fileName)[1];
      const newFileName = `${new Date().getTime()}_${index}`;
      const fileLocation = storageRef.child('estateObjects/' + newFileName + '.' + fileExtension);
      return new Promise(resolve => {
        fileLocation.put(photo.value).on(firebase.storage.TaskEvent.STATE_CHANGED, snapshot => {//let progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
        }, null, () => {
          fileLocation.getDownloadURL().then(url => {
            resolve({
              url: url,
              file: newFileName + '.' + fileExtension
            });
          });
        });
      });
    });
    return Promise.all(photosToSave).then(response => {
      return response;
    });
  } else return Promise.all(photosToSave).then(response => []);
}

答案 1 :(得分:0)

我认为在newFileName上添加同步方法的替代方法可以起作用。

var time = ''; //Global variable
function getTime() {
   if(new Date().getTime() === time){return getTime()}
   else time = new Date().getTime();
   return time;
}

答案 2 :(得分:-1)

我在控制台上运行了此命令,结果是猜测可能是谁出了问题。

 [...Array(7).keys()].map(v=> console.log(new Date().getTime()))

VM676:2 1572510011727
VM676:5 1572510011728

有一个零依赖库uuid,您可以用来确保使用唯一的文件名here

npm install uuid

const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d'