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

标签 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 建立了计算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 被扔给它的任何子进程。谓词只是在 stdout 的字符串中寻找特定的东西。所以它在谓词函数返回 false 时控制台记录输出,否则它停止记录,删除监听器,应该就是这样!

然后是 rmAllListeners 函数:

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

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

进一步阅读:

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

最佳答案

您正在从 proc 而不是 stdout 中移除监听器。 double 出现是因为您将监听器的第二个副本附加到 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')

关于javascript - 为什么这个控制台记录两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51992420/

相关文章:

javascript - 如何在javascript中过滤对象子数组的数组和对象子数组的数组

javascript - Express GraphicsMagick

javascript - JQueryUI 时间微调器上的更改事件是什么?

javascript - ReactJS - 如何避免特定图像在 Lightbox 组件中最大化

node.js - 无法使用Chrome Inspector for Node.js拍摄堆快照

haskell - 如何在 Haskell 中将其更改为 while 循环?

javascript - 选择保存图像的目录

javascript - Nodejs功能评估说明

node.js - 有人可以帮我理解并解决这个 "Failed to install @parcel/transformer-image"吗? (JS)

unit-testing - 函数式编程、SRP、可测试性以及具有静态和实例可变字段的类