Javascript 为什么这个控制台记录两次? 我想做的是:

Javascript 为什么这个控制台记录两次? 我想做的是:,javascript,node.js,functional-programming,monads,console.log,Javascript,Node.js,Functional Programming,Monads,Console.log,我想使用Node在特定的时间以特定的顺序启动两个子进程,控制台在流时记录它们的stdout,偶尔在这两个子进程之间切换 我想要的输出: 当然,这非常容易做到。迫切地。但它也真的很难看,很有状态,只是呃。因此,我尝试纯粹地进行计算,并使用民间故事中的单子(即旧单子)构建了计算,像傻瓜一样用手穿过一个有状态的对象: // main _ :: Task error {childProcs} const main = startProc1({}) .chain(logUntilProc1Is

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

我想要的输出:

当然,这非常容易做到。迫切地。但它也真的很难看,很有状态,只是呃。因此,我尝试纯粹地进行计算,并使用民间故事中的单子(即旧单子)构建了计算,像傻瓜一样用手穿过一个有状态的对象:

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

漂亮多了。如果成功的话,情况也会好得多

我得到的输出:

其中tl;dr:我向它发送一个进程名和从中提取实际子进程的对象,以及一个谓词函数,用于确定向它抛出的任何子进程的
stdout
的控制台日志记录时间。谓词只是从
stdout
中查找字符串中特定的内容。因此,当谓词函数返回false时,控制台将记录输出,否则它将停止记录,删除侦听器,应该如此

然后是
rmAllListeners
函数:

//    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)
}))
//    rmAllListeners :: childProc -> childProc           
const rmAllListeners = proc => (proc.removeAllListeners(), proc.stdout.unref())

后者显然是问题所在。听众,尽管有名字空间,据说被上面的内容抹杀了,但并不是这样。我不知道为什么?!?救命啊

进一步阅读: 对于那些有兴趣看到整件事的人来说,也有一份回购协议:


您正在从
过程中删除侦听器,而不是从
标准输出中删除侦听器。出现双精度是因为您正在将侦听器的第二个副本附加到
proc.stdout
上的“数据”事件

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

太简单了!事后看来,这真是有点拍额头。尤其是因为我成功地将出血的
stdout
放在它旁边。唉。我很欣慰,这与任务计算/fp无关!非常感谢你!事后看来,这么多答案都是(你或你的同事的!)。我们都会像这样陷入困境。一个很好的问题,一个很好的回答。很高兴你能在这么短的时间内登船!问得很好!荣誉
//    rmAllListeners :: childProc -> childProc           
const rmAllListeners = proc => (proc.removeAllListeners(), proc.stdout.unref())
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')