javascript - 为什么这个控制台记录两次?
问题描述
我正在尝试做的事情:
我想使用 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:你可以在这里找到它。
解决方案
您正在从而proc
不是从中删除侦听器stdout
。双打出现是因为您将侦听器的第二个副本附加到proc.stdout
.
添加.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')
推荐阅读
- python - 在 discord.py 中使两个或多个命令能够同时运行
- python - 不和谐机器人每 24 小时自动向每个单独的频道发送挑战
- javascript - 在 switch case 中调用函数
- mysql - 为什么 PopSQL 要求我查看手册?
- reactjs - 使用嵌套记录 json 数据反应渲染错误
- postgresql - Windows 上的 .psqlrc 文件在哪里?
- .net-core - 在 AWS Lambda 函数列表中找不到 Amazon Lambda Tools for .NET 部署的 AWS lambda 函数
- typescript - 验证数组包含具有特定属性和值的每个对象之一
- javascript - 在 React 中,如果状态不影响渲染,是否可以在 setState 之后跳过重新渲染?
- ruby - PG::ConnectionBad:无法将主机名“postgres”转换为地址:没有与主机名关联的地址