异步递归JavaScript函数返回相同的值并突然终止



每次运行以下函数时,我都希望它输出嵌入我的composer.json文件中的不同路径,然后对每个包递归执行此操作。然而,它只是一次又一次地给了我同样的结果。请问我在这里缺了什么?

const packageComposer = async (node) => {
node = node ? __dirname : node;
let composer = fs.readFileSync(node + '/composer.json', 'utf8');
let dependencies = Object.keys(JSON.parse(composer).require);
console.log(node + '/composer.json');
dependencies.forEach(key => {
let dependency = key.split('/');
let dir = node + '/vendor/' + dependency[0] + '/' + dependency[1];
if (fs.existsSync(dir)) {
packageComposer(dir);
}
});
}

Composer.json文件看起来像:

{
"require": {
"php": ">=7.2",
"alek13/slack": "^2.1",
"composer/installers": "^1.7",
"htmlburger/carbon-fields": "^3.3"
}
}

控制台输出:

/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
RangeError: Maximum call stack size exceeded
Exception in PromiseRejectCallback:
/Users/user/Desktop/github/plugin-folder/gulpfile.js:59
}

我想知道为什么你的控制台输出从未显示出包含/vendor的路径,因为你的递归逻辑打算创建一个包含/vendor的路径。然后,我意识到,这是因为这个逻辑:

node = node ? __dirname : node;

是向后的,并且在传递node的值时将始终选择__dirname。因此,每个递归调用最终都会使用相同的node值,从而产生一个最终溢出堆栈的无限循环。

相反,你想要这个:

node = node ? node : __dirname;

三元运算符的MDN描述如下:

condition ? exprIfTrue : exprIfFalse

另一种方法是使用默认参数,并让JS引擎在没有传递任何内容时提供一个值,然后按照以下方式写入:

const packageComposer = async (node = __dirname) => {
...
};

对于任何进一步的调试,我可能会建议使用这个带有日志记录的清理版本,让您了解它的去向:

function packageComposer(node = __dirname) {
// read and parse composer.json using require()
const filename = path.join(node, 'composer.json');
console.log(`About to read ${filename}`);
let composer = require(filename);
const dependencies = Object.keys(composer.require);
console.log("Found dependencies", dependencies);
for (const key of dependencies) {
const pieces = key.split("/");
const dir = path.join(node, 'vendor', dependency[0], dependency[1]);
if (fs.existsSync(dir)) {
console.log(`Calling packageComposer(${dir}) recursively`);
packageComposer(dir);
}
}
}

正如我在评论中所说,这里有几件事看起来很奇怪。执行key.split("/")以获得密钥(如"alek13/slack"(的片段,然后立即将它们重新组合在一起以再次重建"alek13/slack"。不知道为什么要这样做,也不知道当密钥无法分割,并且您有一个像"php"这样不包含"/"的密钥时,会发生什么。