节点 js 中的最大行数:child-process.exec

maximum line count in node js : child-process.exec

问题

Node 的 child-process 有限制吗? 我该如何获取(逐块)一个巨大的命令输出,如 git show with a huge file ?


一般问题

我尝试解析 git show <commit sha> 的结果,并且有一个 巨大的文件(308 344 行)

当 运行 git show > showed_by_git.txt 我有正确的输出,包含所有文件,结果为 118 667 行

当 运行 节点的 child-process 我只检索 32 602 行 ...


我的测试及其结果

我简化了我的代码并使用 child-process 来计算字符数和行数 它在停止流程之前解决。

结果显示它停止在 32 000+ 行而不是预期的 118 667

如果您的存储库包含最近提交的一些 HUUUGE 文件,您可以在家重现

const childProcess = require('child_process')

function fetchCommand (command) {
  return new Promise((resolve, reject) => {
    const sub = childProcess.exec(command)

    let chars = 0
    let lines = 0

    sub.stdout.on('data', function (chunk) {
      chars += chunk.length
      lines += chunk.split('\n').length
      console.log('chars:' + chars + ' lines:' + lines)
      // logs the char and line count on each chunk of data, 
      // then 'forgets' the data : no memory overloading
    })
    sub.stdout.on('close', function () {
      console.log('CLOSED')
    })
    sub.stderr.on('error', function (err) {
      console.log('ERROR: ' + err.message)
    })
  })
}

fetchCommand('git show').catch(err => console.log(err))

输出

这是输出:

C:\Users\guill\.code\git2stats>node examples/fetchTest.js
chars:4096 lines:126
chars:73728 lines:2117
chars:131072 lines:3772
chars:176128 lines:5176
chars:229376 lines:6560
chars:262144 lines:7663
chars:323584 lines:9171
chars:393216 lines:11304
chars:462848 lines:13483
chars:475136 lines:13849
chars:507904 lines:14916
chars:536576 lines:15839
chars:573440 lines:17028
chars:618496 lines:18484
chars:688128 lines:20539
chars:737280 lines:22000
chars:765952 lines:22930
chars:794624 lines:23860
chars:823296 lines:24794
chars:892928 lines:26976
chars:962560 lines:29104
chars:991232 lines:30003
chars:1032192 lines:31292
chars:1073152 lines:32602
CLOSED

您可以看到它停在 32 602 行,而这个特定的 git show 有 118 667 行要显示

最后一块

我检查了最后一块数据,看它是否对大文件做了一些特殊的事情, 但我可以确认它停在文件中间


上下文

我正在写一个 git statistics tools, 这个项目进展顺利 因为我可以解析 git log --stat 然后 git show <commit sha> 每次提交 return 令人满意的 json

这是我以前不知道的某种节点 foot-gun。

是的,有一个限制。它配置有 maxBuffer 选项 (see docs),如果您愿意,可以将其设置为 Infinity。可以将其设置为 Infinity 的想法未记录在案。

const sub = childProcess.exec(command, { maxBuffer: Infinity });

我真的很震惊这个限制的存在,我现在将被迫对大量代码进行代码审查,以找到使用 child_process 模块的每个地方,看看我是否需要添加 maxBuffer 选项。

把它当作一个如何设计糟糕界面的例子。

小注

您可能想要处理 sub.on('exit', code => {})sub.on('close') 这是同一件事,因此您可以检查 Git 的退出状态并在状态不为 0 时引发错误. 像这样:

sub.on('exit', code => {
    if (code == 0) {
        resolve(...);
    } else {
        reject(...);
    }
});