最近在用 node.js 寫一些系統管理層面的程式,有些複雜的工作需要 fork process 來做,主要的 process 用來跑 Web 跟處理主要流程,所以不打算做太多額外的工作。
1 | var child = require( 'child_process' ).fork( './child.js' ); |
在這裡實作的過程中想到一些設計,第一個部份是我的 child 應該設計成一個適合 require 的子模組,由他自己提供輔助函式,也由該模組 fork 自己。
1 2 3 | var child = require( './child.js' ); child.start(); child.stop(); |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | var process; exports.start = function () { var cp = require( 'child_process' ); process = cp.fork( './child.js' ); child.send( 'message' , {cmd: 'start' }); } exports.stop = function () { if (process) process.kill(); } process.on( 'message' , function (msg) { if (msg.cmd == 'start' ) { // child process start // do something } }); |
由於 fork 出去的 child process 是一個子模組,所以對 parent 來說還是有一些事情想要呼叫 child 來做。依照習慣要寫一些匿名函式當參數,意思就是這個函式希望是在 child process 去跑,而不是單純用來當回呼函式使用,結果實際到這邊發現有些事情跟想像的不太一樣,process.send 當參數如果傳函式到 child process 竟然會接不到~。
仔細想想好像也不完全無道理,由於要 IPC,而 json 對函式的轉換好像本來就不太支援。
範例繼續延續上面的,這範例 msg 將收不到傳過去的函式。
1 2 3 4 5 | .. child.helper( function (res) { // ... }); .. |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var process; exports.start = function () { var cp = require( '' child_process); process = cp.fork( './child.js' ); child.send( 'message' , {cmd: 'start' }) } exports.stop = function () { if (process) process.kill(); } exports.helper = function (handler) { process.send({cmd: 'helper' , handler: handler}); }); process.on( 'message' , function (msg) { if (msg.cmd == 'start' ) { // child process start // do something } else if (msg.cmd == 'helper' ){ console.log(msg); // { msg: 'helper' } } }); |
這裡就讓我想到曾經看過一篇文章…撰寫乾淨的 eval 程式碼的技巧,因此就依樣畫葫蘆…就能動了!
只是要注意透過這種方式傳過去的函式所能存取到的變數已經不是表面上看到的了。而是透過 eval 執行時的 child process 的 context 了。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | exports.helper = function (handler) { process.send({cmd: 'helper' , handler: handler.toString()}); }); process.on( 'message' , function (msg) { if (msg.handler) { eval( 'var handler = ' + msg.handler); } if (msg.cmd == 'start' ) { // child process start // do something } else if (msg.cmd == 'helper' && handler){ handler([1, 2, 3]); } }); |