免责声明,自我回答的帖子,希望能节省其他人的时间。
设置:
我一直在使用 chrome 的文件系统 API 实现[1] [2] [3]。
这需要启用标志chrome://flags/#native-file-system-api。
对于初学者,我想递归读取目录并获取文件列表。这很简单:
paths = [];
let recursiveRead = async (path, handle) => {
let reads = [];
// window.handle = handle;
for await (let entry of await handle.getEntries()) { // <<< HANGING
if (entry.isFile)
paths.push(path.concat(entry.name));
else if (/* check some whitelist criteria to restrict which dirs are read*/)
reads.push(recursiveRead(path.concat(entry.name), entry));
}
await Promise.all(reads);
console.log('done', path, paths.length);
};
chooseFileSystemEntries({type: 'openDirectory'}).then(handle => {
recursiveRead([], handle).then(() => {
console.log('COMPLETELY DONE', paths.length);
});
});
我还实现了一个非递归的 while-loop-queue 版本。最后,我实现了一个节点fs.readdir
版本。所有 3 种解决方案都适用于小目录。
问题:
但后来我尝试在铬源代码的一些子目录('base'、'components'和'chrome')上运行它;3 个子目录总共包含约 63,000 个文件。虽然节点实现运行良好(令人惊讶的是,它在运行之间使用了缓存结果,导致在第一次运行之后立即运行),两种浏览器实现都挂起。
尝试调试:
有时,他们会返回完整的 63k 文件并按'COMPLETLEY DONE'
预期打印。但大多数情况下(90% 的时间)他们会在挂起之前读取 10k-40k 文件。
我深入挖掘了悬挂,显然这for await
条线是悬挂的。所以我window.handle = handle
在 for 循环之前添加了这一行;当函数挂起时,我直接在浏览器控制台中运行了 for 循环,它工作正常!所以现在我被困住了。我似乎有随机挂起的工作代码。