首页 > 解决方案 > 为什么这个控制台记录两次?

问题描述

我正在尝试做的事情:

我想使用 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!`

 

当然,这非常容易做到。势在必行。但它也非常丑陋和有状态,而且只是 urgh。所以我试图纯粹地这样做,并使用Task来自folktale(旧的那个)的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哪个子进程的多长时间被扔了。谓词只是在字符串中寻找特定的东西 from stdout。因此,当谓词函数返回 false 时,它​​会在控制台记录输出,否则它会停止记录,删除侦听器,应该就是这样!

 

然后是rmAllListeners功能:

 

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

 

后者显然是问题所在。侦听器尽管被命名空间并被上述内容所消灭,但实际上并不存在。而且我不知道为什么?!?帮助!

 

进一步阅读:

对于那些有兴趣查看整个内容的人来说,它也有一个 repo:你可以在这里找到它

 

标签: javascriptnode.jsfunctional-programmingmonadsconsole.log

解决方案


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

添加.stdoutrmAllListeners我修复它:

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')

推荐阅读