【问题标题】:Awaiting a function that calls an async function recursively等待递归调用异步函数的函数
【发布时间】:2020-09-08 00:21:23
【问题描述】:

我有一个看起来像这样的函数:

function populateMap(directory: string, map, StringMap) {
    fs.promises.readdir(directory).then(files: string[]) => {
        files.forEach(file: string) => {
            const fullPath = path.join(directory, file);
            fs.stat(fullPath, (err: any, stats: any) => {
                if (stats.isDirectory()) {
                   populateFileMap(fullPath, fileMap);
                } else {
                   fileMap[file] = fullPath;
                }
            });
        });
    });
}

我想要做的是递归遍历父目录并将文件名映射存储到它们的路径。我知道这是有效的,因为如果我在 fileMap[file] = fullPath 下放置一个 console.log(fileMap),在目录中最深的文件之后,列表就会正确填充。

在调用此函数的文件中,我希望能够拥有完整的地图

function populateMapWrapper(dir: string) {
    const fileMap: StringMap = {};

    populateMap(dir, fileMap);

    //fileMap should be correctly populated here
}

我尝试过使 populateMap 异步,将 .then() 添加到包装函数中调用它的位置,但如果我在 then() 函数中使用 console.log(fileMap),则 fileMap 为空。

我不确定这是因为 javascript 如何传递变量,还是我对 Promise 的理解存在差距,但我想知道是否有其他方法可以做到这一点。

【问题讨论】:

  • 是的,将回调样式转换为 Promise 是一个好主意,就像将其设置为 async function 一样,您可以在其中 await 这些 Promise。还有don't use forEach.

标签: javascript typescript promise es6-promise fs


【解决方案1】:

一个问题是fs.stat 没有返回承诺。您还需要使用fs.promises.stat。此外,在使用 Promise 时要小心使用 forEach,因为它不会为每个 forEach 回调使用 await。您可以改用 mapPromise.all()

一个解决方案:

function populateMap(directory: string, map) {
  return fs.promises.readdir(directory).then((files: string[]) => {
    return Promise.all(
      files.map((file: string) => {
        const fullPath = path.join(directory, file);
        return fs.promises.stat(fullPath).then(stats => {
          if (stats.isDirectory()) {
            return populateMap(fullPath, map);
          } else {
            map[file] = fullPath;
          }
        })
      }))
  })
}

那么你必须在包装器中使用await

async function populateMapWrapper(dir: string) {
    const fileMap: StringMap = {};

    await populateMap(dir, fileMap);

    //fileMap should be correctly populated here
}

但是,更易读的解决方案是尽可能使用await。比如:

async function populateMap (directory: string, map) {
  const files = await fs.promises.readdir(directory)
  for (const file of files) {
    const fullPath = path.join(directory, file)
    const stats = await fs.promises.stat(fullPath)
    if (stats.isDirectory()) {
      await populateMap(fullPath, map)
    } else {
      map[file] = fullPath
    }
  }
}

【讨论】:

  • 那不是答案,那是评论(或提示)
  • 感谢您的详细解答。我能够遵循您的建议并且效果很好。
猜你喜欢
  • 2022-01-27
  • 1970-01-01
  • 2016-09-21
  • 1970-01-01
  • 1970-01-01
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
相关资源
最近更新 更多