简体   繁体   English

等待递归调用异步 function 的 function

[英]Awaiting a function that calls an async function recursively

I have a function that looks like this:我有一个看起来像这样的 function:

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

What I want to do is recursively walk through the parent directory and store a map of file names to their paths.我想要做的是递归遍历父目录并将文件名的 map 存储到它们的路径中。 I know this is working because if I put a console.log(fileMap) under fileMap[file] = fullPath, after the deepest file in the directory, the list is properly populated.我知道这是有效的,因为如果我在 fileMap[file] = fullPath 下放置一个 console.log(fileMap),在目录中最深的文件之后,列表就会正确填充。

In the file that calls this function, I want to be able to have the full map as such在调用此 function 的文件中,我希望能够拥有完整的 map

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

    populateMap(dir, fileMap);

    //fileMap should be correctly populated here
}

I've tried making populateMap asynchronous, adding a.then() to where it's called in the wrapper function, but if I console.log(fileMap) in the then() function, the fileMap is empty.我尝试过使populateMap异步,将a.then()添加到包装器function中调用它的位置,但是如果我在then() function中使用console.log(fileMap),则fileMap为空。

I'm not sure if this is because of how javascript passes variables or if there's a gap in my understanding of promises, but I'm wondering if there's an alternative way to do this.我不确定这是否是因为 javascript 如何传递变量,或者我对承诺的理解存在差距,但我想知道是否有其他方法可以做到这一点。

One problem is that fs.stat doesn't return a promise.一个问题是fs.stat没有返回 promise。 You need to also use fs.promises.stat .您还需要使用fs.promises.stat Also, when working with promises be careful about using forEach , because it doesn't await for each of the forEach callbacks.此外,在使用 Promise 时要小心使用forEach ,因为它不会await每个forEach回调。 You could instead use map with Promise.all()您可以将mapPromise.all()一起使用

One solution:一种解决方案:

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

Then you would have to use await in the wrapper:然后你必须在包装器中使用await

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

    await populateMap(dir, fileMap);

    //fileMap should be correctly populated here
}

However, a more readable solution would be to make use of await whenever possible.但是,更易读的解决方案是尽可能使用await Something like:就像是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM