【问题标题】:Asynchronous recursive JavaScript function returns same value and terminates abruptly异步递归 JavaScript 函数返回相同的值并突然终止
【发布时间】:2022-01-25 15:02:03
【问题描述】:

每次我运行以下函数时,我希望它输出嵌入在我的 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
}

【问题讨论】:

  • 您可以添加更多上下文吗? composer.json 看起来像什么?你保存文件了吗?
  • 为什么是async这个函数?
  • 重申@Andy,它没有在正文中执行任何异步操作(甚至没有等待递归调用)。我认为这里有两个级别的问题:(1)关于什么应该是异步以及如何处理异步递归,(2)关于文件解析出了什么问题以及关于解析什么的假设会发现。我建议以相反的顺序攻击这些。为了解决后者,请发布文件中的一些行和一些控制台输出。
  • @jfriend00 我问是因为我不知道。您的评论既没有帮助也没有解释我可以做得更好的地方。通过显示我的 console.log 的输出,我提供了有关如何尝试使用它的有用上下文,您至少可以为我指明正确的方向。
  • 安迪问为什么是async 而你还没有回答他。这与答案有关。我删除了我之前对该主题的评论,因为它有点刻薄。我很抱歉。

标签: javascript node.js asynchronous recursion


【解决方案1】:

我想知道为什么您的控制台输出从不显示包含/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);
        }
    }
}

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

【讨论】:

    猜你喜欢
    • 2014-05-01
    • 2017-09-24
    • 1970-01-01
    • 2021-03-22
    • 2018-02-24
    • 2023-03-11
    • 1970-01-01
    • 2023-03-28
    • 2015-08-24
    相关资源
    最近更新 更多