如何在循环内累积承诺回报

时间:2018-11-04 12:46:08

标签: loops recursion promise

例如,我试图递归获取cordova文件夹中所有项目的文件大小,所以我有类似的东西

getDirSize(path) {
    return this.listDir(path).then((data) => {
        let size = 0

        data.dirs.map((dir) => {
            size += this.getRecursiveSize(dir.files)
        })

        if (data.files.length) {
            size += this.getRecursiveSize(data.files)
        }

        return size
    })
}

getRecursiveSize(files) {
    let size = 0

    files.map((item) => {
        this.getFileMeta(item.url).then((file) => {
            size += file.size
        })

        if (item.files) {
            size += this.getRecursiveSize(item.files)
        }
    })

    return size
}

通过

调用
getDirSize(path).then((size) => {
    console.log(size)
})

但是由于getFileMeta()是一个承诺,所以这行不通,我知道promise.all(),但不确定如何正确使用它来获得所有物品的最终尺寸。

1 个答案:

答案 0 :(得分:0)

因此,您可以使用map和Promise.all将对getFileMeta()的所有调用放入数组中。 Promise.all将采用承诺的数组,并将每个数组中解析的内容设置为数组。

因此,在这种情况下,您将获得一个fileMetaData数组,您可以将其用作任何其他数组(在Promise.all完成后-使用.then或await)。

如果它(又名getFileMeta)已经返回了诺言:

const filesMetaData = Promise.all(files.map(file => this.getFileMeta(file.url)))
filesMetaData.then(
fileMetaData // became an array here because of Promise.all
=> fileMetaData.reduce((accumulatedSize, file) => {
  accumulatedSize += file.size
  return accumulatedSize
})

或者,如果您使用的是更高版本的节点,则可以将异步JavaScript与async/await一起使用,这非常酷!

使用伪代码,策略是:

  1. 等待获取有关每个文件之一的fileMetaData。
  2. 获取每个原始文件的大小并将其添加到0。
  3. 检查其中是否有嵌套文件。
  4. 如果是这样,请将这些文件添加到文件列表中以递归方式运行此功能。
  5. 如果没有文件具有嵌套文件,则返回父文件的计数。

const recursivelyGetSize = async (files) => {
  if (!files.length) { // recursive condition 
    return 0
  }
  const filesMetaData = await Promise.all(
    files.map(file => this.getFileMeta(file.url))
  ) // became an array of files here because of Promise.all
  const count = fileMetaData.reduce(
    (accumulatedSize, file) => accumulatedSize + file.size,
    0
  )
  const filesWithFiles = filesMetaData.filter(file => file.files.length)
  if (!filesWithFiles.length) {
    return count
  }
  // not sure if you need await here because
  // return by default has a built in await
  return count + await recursivelyGetSize([
      ...filesWithFiles.map(file => file.files)
    ])
}