Javascript 等待递归调用异步函数的函数

Javascript 等待递归调用异步函数的函数,javascript,typescript,promise,es6-promise,fs,Javascript,Typescript,Promise,Es6 Promise,Fs,我有一个函数如下所示: function populateMap(directory: string, map, StringMap) { fs.promises.readdir(directory).then(files: string[]) => { files.forEach(file: string) => { const fullPath = path.join(directory, file); fs

我有一个函数如下所示:

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;
                }
            });
        });
    });
}
我要做的是递归地遍历父目录,并将文件名映射存储到它们的路径。我知道这是可行的,因为如果我将一个console.log(fileMap)放在fileMap[file]=fullPath下,在目录中最深的文件之后,列表就会正确填充

在调用此函数的文件中,我希望能够获得完整的映射

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

    populateMap(dir, fileMap);

    //fileMap should be correctly populated here
}
我尝试过使populateMap异步,在包装函数中调用它的地方添加一个.then(),但是如果在then()函数中使用console.log(fileMap),则fileMap是空的


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

一个问题是,
fs.stat
不返回承诺。您还需要使用
fs.promises.stat
。另外,在使用promises时,请小心使用
forEach
,因为它不会等待
forEach
的每个回调。您可以将
map
Promise.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;
          }
        })
      }))
  })
}
然后您必须在包装器中使用
wait

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

    await populateMap(dir, fileMap);

    //fileMap should be correctly populated here
}
然而,一个更具可读性的解决方案是尽可能使用
wait
。比如:

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
    }
  }
}

这不是一个答案,这是一个评论(或提示),谢谢你的详细回答。我能够按照您的建议进行操作,效果很好。是的,将回调样式转换为承诺是一个好主意,将其作为一个
异步函数
,您可以
等待这些承诺。和。