为什么该控制台记录两次?

时间:2018-08-23 18:45:58

标签: javascript node.js functional-programming monads console.log

我正在尝试做的事情:

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

当然,这很容易做到。 紧急地。但这也真的很丑且有状态,只是敦促。因此,我试图纯粹地做到这一点,并使用了来自于民间传说的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:是向我发送一个进程名称和一个对象,该对象将从中抽取实际的子进程,还有一个谓词函数,用于决定控制台日志{{ 1}}的任何子进程。谓词只是在stdout的字符串中查找特定内容。因此,当谓词函数返回false时,它会控制台记录输出,否则它将停止记录,删除监听器,应该就是这样!

然后是stdout函数:

rmAllListeners

后者显然是问题所在。侦听器尽管已被命名为命名空间,并且据称已被上述内容淘汰,但它们并未存在。而且我不知道为什么?!?救命!

进一步阅读:

对于有兴趣看完整本书的人也有一个回购清单:you can find it here

1 个答案:

答案 0 :(得分:2)

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

.stdout中添加rmAllListeners可以为我解决此问题:

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')
相关问题