处理大量承诺的最有效方式?

Posted

技术标签:

【中文标题】处理大量承诺的最有效方式?【英文标题】:Most efficient way of handling high volumes of promises? 【发布时间】:2020-03-19 13:48:20 【问题描述】:

处理大量承诺的最有效方法是什么?我提出了 2 个解决方案,并确定 Solution 2(使用 bluebird 的 promise.map)更快。

解决方案 1(每个文件约 38 毫秒)

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

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

【问题讨论】:

您不受“大量承诺”的约束。您的解决方案之间的巨大区别在于,第一个顺序读取所有文件标签,而第二个一次读取 5 个,显然更快。你选择了多少个文件? @Bergi 我使用 100 个 mp3 文件进行了基本测试 然后您可以尝试将concurrency 设置提高得更高,应该会看到一些进一步的改进(尽管不是线性的)。 @Bergi 如何在开始遇到内存问题之前确定我可以使用的最大 concurrency 值? 我不认为你可以 - 这取决于太多因素。 【参考方案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
    )
  
)

【讨论】:

以上是关于处理大量承诺的最有效方式?的主要内容,如果未能解决你的问题,请参考以下文章

在(“message”)处理程序上定义Socket.io的最有效方法

Promise.all 和 Promise.race 有效地使所有承诺“得到处理”,这是一种记录在案的行为吗?

通过网络连续传输图像的最有效方式

使用 JSON 对象解析和处理大文件的更有效方法

从邻接表创建树的最有效方法

Scala:基于文件列表处理文件夹中文件的最有效方法