为什么这个控制台记录两次?
Why does this console log twice?
我想做什么:
我想使用 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!`
当然超级容易做到。 势在必行。但它也真的很丑陋和有状态而且只是呃。所以我试图纯粹地做到这一点,并使用 folktale 中的 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: 是我向它发送进程名称和从中提取实际子进程的对象,以及用于决定控制台记录多长时间的谓词函数stdout
被扔给它的任何子进程。谓词只是在 stdout
的字符串中寻找特定的东西。因此它在谓词函数 returns 为假时控制台记录输出,否则它停止记录,删除侦听器,应该是这样!
然后是 rmAllListeners
函数:
// rmAllListeners :: childProc -> childProc
const rmAllListeners = proc => (proc.removeAllListeners(), proc.stdout.unref())
后者显然是问题所在。听众,尽管被命名空间命名并被上述内容抹杀,但实际上并没有。我不知道为什么?!?求助!
进一步阅读:
对于那些有兴趣看到整个事情的人来说,还有一个回购:you can find it here。
您正在从 proc
而不是 stdout
中删除侦听器。双打出现是因为您将侦听器的第二个副本附加到 proc.stdout
上的 'data' 事件。
在 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')
我想做什么:
我想使用 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!`
当然超级容易做到。 势在必行。但它也真的很丑陋和有状态而且只是呃。所以我试图纯粹地做到这一点,并使用 folktale 中的 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: 是我向它发送进程名称和从中提取实际子进程的对象,以及用于决定控制台记录多长时间的谓词函数stdout
被扔给它的任何子进程。谓词只是在 stdout
的字符串中寻找特定的东西。因此它在谓词函数 returns 为假时控制台记录输出,否则它停止记录,删除侦听器,应该是这样!
然后是 rmAllListeners
函数:
// rmAllListeners :: childProc -> childProc
const rmAllListeners = proc => (proc.removeAllListeners(), proc.stdout.unref())
后者显然是问题所在。听众,尽管被命名空间命名并被上述内容抹杀,但实际上并没有。我不知道为什么?!?求助!
进一步阅读:
对于那些有兴趣看到整个事情的人来说,还有一个回购:you can find it here。
您正在从 proc
而不是 stdout
中删除侦听器。双打出现是因为您将侦听器的第二个副本附加到 proc.stdout
上的 'data' 事件。
在 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')