我有一个库,用于扫描目录以查找远程服务器上的文件。它返回一个Promise,如下所示:
client.scanRemoteDirectory(path)
.then(files => {
console.log(files)
})
我试图写一个递归方法来扫描目录和子目录。但是我遇到了一些异步问题。我的功能是这样的:
const scanDir(path) {
// Scan the remote directory for files and sub-directories
return client.scanRemoteDirectory(path)
.then(files => {
for (const file of files) {
// If a sub-directory is found, scan it too
if (file.type === 'directory') {
return scanDir(file.path) // Recursive call
}
}
})
}
const scanDir('some/path')
.then(() => {
console.log('done')
})
然而,由于return
递归方法调用前面的scanDir()
,这会导致该方法仅扫描每个目录中的第一个子目录并跳过其余目录。
例如,如果结构是这样的:
/some/path
/some/path/dirA
/some/path/dirA/subdirA
/some/path/dirB
/some/path/dirB/subdirB
上述方法仅扫描:
/some/path
/some/path/dirA
/some/path/subdirA
由于该方法首先找到dirB
,因此它会完全跳过dirA
及其子项。
如果我只是从return
电话中移除return scanDir(...)
,那么它会扫描所有内容。但是我的最后console.log('done')
太快了,因为它是异步的。
那么我该如何解决这个问题呢?什么是正确的递归Promise方法,我仍然可以保留异步,但也可以递归扫描每个子目录?
答案 0 :(得分:3)
您可能希望在这种情况下使用Promise.all
来运行您的' sub'并行承诺,例如:
function scanDir(path) {
return client.scanRemoteDirectory(path)
.then(all => {
const files = all.where(file => file.type !== 'directory);
const dirs = all.where(file => file.type === 'directory);
return Promise.all(dirs.map(dir => scanDir(dir.path)) // Execute all 'sub' promises in parallel.
.then(subFiles => {
return files.concat(subFiles);
});
});
}
或者,您可以使用reduce
功能运行您的' sub'承诺顺序:
function scanDir(path) {
return client.scanRemoteDirectory(path)
.then(all => {
const files = all.where(file => file.type !== 'directory);
const dirs = all.where(file => file.type === 'directory);
return dirs.reduce((prevPromise, dir) => { // Execute all 'sub' promises in sequence.
return prevPromise.then(output => {
return scanDir(dir.path)
.then(files => {
return output.concat(files);
});
});
}, Promise.resolve(files));
});
}
Async / await绝对是最简单的解决方案:
async function scanDir(path) {
const output = [];
const files = await client.scanRemoteDirectory(path);
for (const file of files) {
if (file.type !== 'directory') {
output.push(file);
continue;
}
const subFiles = await scanDir(file.path);
output = output.concat(subFiles);
}
return output;
}
答案 1 :(得分:0)
我会使then
处理程序异步,以便您可以在循环中使用await
:
const scanDir(path) {
// Scan the remote directory for files and sub-directories
return client.scanRemoteDirectory(path)
.then(async files => {
for (const file of files) {
// If a sub-directory is found, scan it too
if (file.type === 'directory') {
await scanDir(file.path) // Recursive call
}
}
})
}