使用FileReader的promise不会给出所需的延迟结果

时间:2018-02-08 11:27:41

标签: javascript node.js promise es6-promise

使用文件输入元素后,我希望随后上传所选文件。使用FileReader读取文件是异步的,因此我尝试使用promise来推迟上传函数调用。但是,当vm.upload()数组尚未填充时,vm.files会被调用,但它无法正常工作。顺便说一句,承诺没有错误。

为什么承诺不会等待/推迟'?可能是因为我应该更接近异步代码(在map方法中),但我不确定为什么?

  let filesPromise = inputFiles => {
    return new Promise((resolve, reject) => {
      inputFiles.filter(file => !this.queue.some(f => file.name === f.name))
        .map(file => {
          file.__size = humanStorageSize(file.size)

          if (this.noThumbnails || !file.type.startsWith('image')) {
            this.queue.push(file)
          }
          else {
            const reader = new FileReader()
            reader.onload = (e) => {
              let img = new Image()
              img.src = e.target.result
              file.__img = img
              this.queue.push(file)
              this.__computeTotalSize()
            }
            reader.readAsDataURL(file)
          }
          return file
        })

      resolve(inputFiles)
      reject(new Error('An error occurred in filesPromise'))
    })
  }

  filesPromise(eventFiles)
    .then(eventFiles => vm.files.concat(eventFiles))
    .then(() => vm.upload())
    .catch(error => console.log('An error occurred: ', error))

1 个答案:

答案 0 :(得分:0)

正如@baao评论的那样,包含异步代码(FileReader事件)的map方法将继续而不是等待。要解决这个问题,需要将FileReader放入Promise并继续使用map与Promises一起构建一个由Promise-elements组成的数组。在此阵列上,您随后可以运行Promise.all。此代码有效:

  let filesReady = [] // List of image load promises
  files = inputFiles.filter(file => !this.queue.some(f => file.name === f.name))
    .map(file => {
      initFile(file)
      file.__size = humanStorageSize(file.size)
      file.__timestamp = new Date().getTime()

      if (this.noThumbnails || !file.type.startsWith('image')) {
        this.queue.push(file)
      }
      else {
        const reader = new FileReader()
        let p = new Promise((resolve, reject) => {
          reader.onload = (e) => {
            let img = new Image()
            img.src = e.target.result
            file.__img = img
            this.queue.push(file)
            this.__computeTotalSize()
            resolve(true)
          }
          reader.onerror = (e) => {
            reject(e)
          }
        })

        reader.readAsDataURL(file)
        filesReady.push(p)
      }

      return file
    })

  if (files.length > 0) {
    vm.files = vm.files.concat(files)
    Promise.all(filesReady)
      .then(() => vm.upload())
      .catch(error => console.log('An error occurred: ', error))
  }