为什么这个控制台记录两次?

Why does this console log twice?

我想做什么:

我想使用 Node 在特定时间以特定顺序启动两个子进程,控制台在它们流式传输时记录它们的 stdout,偶尔在两者之间切换。

我想要的输出:

`Proc 1 log # 1`
`Proc 1 log # 2`
`Proc 1 log # 3`
`Proc 1 log # 4`
`Proc 2 log # 1`
`Proc 2 log # 2`
`Proc 2 log # 3`
`Proc 2 log # 4`
`Proc 1 log # 9`
`Proc 1 log # 10`
`Proc 1 log # 11`
`Proc 1 log # 12`
`Proc 1 log # 13`
`Proc 1 log # 14`
`Proc 1 log # 15`
`All procs have finished!`

当然超级容易做到。 势在必行。但它也真的很丑陋和有状态而且只是呃。所以我试图纯粹地做到这一点,并使用 folktale 中的 Task monad(旧的,即旧的)建立了计算,像笨蛋一样手动穿过有状态对象:

//    main _ :: Task error {childProcs}
const main = startProc1({})
  .chain(logUntilProc1IsReady)
  .chain(startProc2)
  .chain(logUntilProc2IsReady)
  .chain(logUntilProc1IsFinished)

漂亮多了。如果有效的话也会好很多!

我得到的输出:

`Proc 1 log # 1`                                       
`Proc 1 log # 2`
`Proc 1 log # 3`
`Proc 1 log # 4`
`Proc 2 log # 1`
`Proc 1 log # 6`   // <-- These should not be logged
`Proc 2 log # 2`
`Proc 1 log # 7`
`Proc 2 log # 3`
`Proc 1 log # 8`
`Proc 2 log # 4`
`Proc 1 log # 9`
`Proc 1 log # 10`  // <-- now it's logging twice! :confounded:
`Proc 1 log # 10`
`Proc 2 log # 6`
`Proc 1 log # 11`
`Proc 1 log # 11`
`Proc 2 log # 7`
`Proc 1 log # 12`
`Proc 1 log # 12`
`Proc 2 log # 8`
`Proc 1 log # 13`
`Proc 1 log # 13`
`Proc 2 log # 9`
`Proc 1 log # 14`
`Proc 1 log # 14`
`Proc 2 log # 10`
`All procs have finished!`

我做过的事情:

这里是日志函数:

//    logStreamUntil :: int -> (a -> bool) -> proc -> string -> Task error State () {childProcs}
const logStreamUntil = curry((predFunc, procName, procObj) => 
  new Task ((_, res) => {
    const proc = procObj[procName]
    const logUntilPred = data =>
      predFunc(data) 
        ? (rmAllListeners(proc), res(procObj))
        : console.log(data)
    proc.stdout.on('data', logUntilPred)
}))

其中 tl;dr: 是我向它发送进程名称和从中提取实际子进程的对象,以及用于决定控制台记录多长时间的谓词函数stdout 被扔给它的任何子进程。谓词只是在 stdout 的字符串中寻找特定的东西。因此它在谓词函数 returns 为假时控制台记录输出,否则它停止记录,删除侦听器,应该是这样!

然后是 rmAllListeners 函数:

//    rmAllListeners :: childProc -> childProc           
const rmAllListeners = proc => (proc.removeAllListeners(), proc.stdout.unref())

后者显然是问题所在。听众,尽管被命名空间命名并被上述内容抹杀,但实际上并没有。我不知道为什么?!?求助!

进一步阅读:

对于那些有兴趣看到整个事情的人来说,还有一个回购:you can find it here

您正在从 proc 而不是 stdout 中删除侦听器。双打出现是因为您将侦听器的第二个副本附加到 proc.stdout 上的 'data' 事件。

rmAllListeners 中添加 .stdout 为我修复了它:

diff --git a/why-log-twice.js b/why-log-twice.js
index 276d15c..6c15467 100644
--- a/why-log-twice.js
+++ b/why-log-twice.js
@@ -7,7 +7,7 @@ const PROC_ONE_PATH = `node child-proc "Proc 1 log # "`
 const PROC_TWO_PATH = `node child-proc "Proc 2 log # "`

 //    rmAllListeners :: childProc -> childProc           
-const rmAllListeners = proc => (proc.removeAllListeners(), proc.stdout.unref())
+const rmAllListeners = proc => (proc.stdout.removeAllListeners(), proc.stdout.unref())

 //    procIsReady :: string -> bool
 const procIsReady = str => str.includes('5')