我有一个函数,看起来像这样:
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)放在fileMapfile = 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传递变量的方式,还是在我对promises的理解上存在差距,但我想知道是否有其他方法可以做到这一点。
发布于 2020-05-21 19:27:04
一个问题是fs.stat不返回承诺。您还需要使用fs.promises.stat。此外,在使用promises时要小心使用forEach,因为它不会为每个forEach回调使用await。您可以将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;
}
})
}))
})
}然后,您必须在包装器中使用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
}
}
}https://stackoverflow.com/questions/61933348
复制相似问题