我有一个看起来像这样的函数:
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如何传递变量,还是我对promise的理解是否存在差距,但是我想知道是否还有其他方法可以做到这一点。
答案 0 :(得分:1)
一个问题是fs.stat
没有返回承诺。您还需要使用fs.promises.stat
。另外,在使用Promise时,请谨慎使用forEach
,因为对于每个await
回调而言,它并不是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;
}
})
}))
})
}
然后,您必须在包装器中使用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
}
}
}