处理大量 Promise 的最有效方法是什么?

6
什么是处理大量Promise的最有效方法?我想出了2种解决方案,并确定使用bluebird的promise.map的解决方案2更快。 解决方案1(每个文件约38ms)。

readFile(file) {
  return new Promise((resolve, reject) => {
    jsmediatags.read(file, {
      onSuccess: resolve,
      onError: reject
    })
  })
}

async readFilesHandler() {
  console.time('readFilesHandler timer')
  const fileArray = Array.from(this._fileSelectInput.files)
  const tracksArray = []

  for (let file = 0; file < fileArray.length; file++) {
    await this._readFile(fileArray[file]).then(tags => {
      tracksArray.push({
        id: file + 1,
        title: tags.tags.title || undefined,
        artist: tags.tags.artist || undefined,
        album: tags.tags.album || undefined,
        year: tags.tags.year || undefined
      })
    })
  }
  this.dispatchEvent(new CustomEvent('tracks-selected', {
    detail: tracksArray
  }))
  console.time('readFilesHandler timer') // ~38ms/file
}

解决方案2(每个文件约32毫秒)

_readFiles() {
  console.time('_readFiles timer')
  const fileArray = Array.from(this._fileSelectInput.files)

  window.Promise.map(fileArray, file => {
    return new Promise((resolve, reject) => {
      jsmediatags.read(file, {
        onSuccess: resolve,
        onError: reject
      })
    })
  }, {
    concurrency: 5
  }).then(tags => {
    const results = tags.map((tag, index) => ({
      id: index + 1,
      title: tag.tags.title || undefined,
      artist: tag.tags.artist || undefined,
      album: tag.tags.album || undefined,
      year: tag.tags.year || undefined
    }))
    this.dispatchEvent(new CustomEvent('tracks-selected', {
      detail: results
    }))
  })
  console.timeEnd('_readFiles timer') // ~32ms/file
}

有没有更高效的方法来实现相同的结果?


1
你不受“承诺数量过多”的限制。你的解决方案之间的巨大区别在于第一个按顺序读取所有文件标签,而第二个一次读取5个,显然更快。你选择了多少个文件? - Bergi
@Bergi 我使用了100个mp3文件进行了基本测试。 - jordan
然后,您可以尝试将“并发”设置提高到更高的水平,应该会看到一些进一步的改进(虽然不是线性的)。 - Bergi
@Bergi,我该如何确定在开始运行之前可以使用的最大“并发”值,以避免内存问题? - jordan
1
我认为你无法做到 - 这取决于太多因素了。 - Bergi
显示剩余3条评论
1个回答

1
你可以使用Promise.allSettled()
整个 Promise 数组会在最慢的单个 Promise 解决后尽快解决。
const bucket = await Promise.allSettled(fileArray.map(file => this._readFile(file)))

bucket.forEach(file => {
  if (file.value) {
    const tags = file.value;
    tracksArray.push({
      id: file + 1,
      title: tags.tags.title || undefined,
      artist: tags.tags.artist || undefined,
      album: tags.tags.album || undefined,
      year: tags.tags.year || undefined
    })
  }
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接