<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # 子進程模塊 我們可以使用 Node 的`child_process`模塊來簡單地創造子進程,子進程之間可以通過消息系統簡單的通信。 <br> `child_process`模塊通過在一個子進程中執行系統命令,賦予我們使用操作系統功能的能力。 <br> 我們可以控制子進程的輸入流,并監聽它的輸出流。我們也可以修改傳遞給底層 OS 命令的參數,并得到任意我們想要的命令輸出。舉例來說,我們可以將一條命令的輸出作為另一條命令的輸入(正如 Linux 中那樣),因為這些命令的所有輸入和輸出都能夠使用[Node.js 流](https://medium.freecodecamp.com/node-js-streams-everything-you-need-to-know-c9141306be93)來表示。 <br> # 衍生的子進程 `spawn`函數會在一個新的進程中啟動一條命令,我們可以使用它來給這條命令傳遞任意參數。比如,下面的代碼會衍生一個執行`pwd`命令的新進程。 ~~~ const { spawn } = require('child_process'); const child = spawn('pwd'); ~~~ 我們簡單地從`child_process`模塊中解構`spawn`函數,然后將系統命令作為第一個參數來執行該函數。 <br> `spawn`函數(上面的`child`對象)的執行結果是一個`ChildProcess`實例,該實例實現了[EventEmitter API](https://medium.freecodecamp.com/understanding-node-js-event-driven-architecture-223292fcbc2d)。這意味著我們可以直接在這個子對象上注冊事件處理器。比如,當在子進程上注冊一個`exit`事件處理器時,我們可以在事件處理函數中執行一些任務: ~~~ child.on('exit', function (code, signal) { console.log('child process exited with ' + `code ${code} and signal ${signal}`); }); ~~~ 上面的處理器給出了子進程的退出`code`和`signal`,這兩個變量可以用來終止子進程。子進程正常退出時`signal`變量為 null。 <br> `ChildProcess`實例上還可以注冊`disconnect`、`error`、`close`和`message`事件。 * `disconnect`事件在父進程手動調用`child.disconnect`函數時觸發。 * 如果進程不能被衍生或者殺死,會觸發`error`事件。 * `close`事件在子進程的`stdio`流關閉時觸發。 * `message`事件最為重要。它在子進程使用`process.send()`函數來傳遞消息時觸發。這就是父/子進程間通信的原理。下面將給出一個例子。 <br> 每一個子進程還有三個標準`stdio`流,我們可以分別使用`child.stdin`、`child.stdout`和`child.stderr`來使用這三個流。 <br> 當這幾個流被關閉后,使用了它們的子進程會觸發`close`事件。這里的`close`事件不同于`exit`事件,因為多個子進程可能共享相同的`stdio`流,因此一個子進程退出并不意味著流已經被關閉了。 <br> 既然所有的流都是事件觸發器,我們可以在歸屬于每個子進程的`stdio`流上監聽不同的事件。不像普通的進程,在子進程中,`stdout`/`stderr`流是可讀流,而`stdin`流是可寫的。這基本上和主進程相反。這些流支持的事件都是標準的。最重要的是,在可讀流上我們可以監聽`data`事件,通過`data`事件可以得到任一命令的輸出或者執行命令過程中發生的錯誤: ~~~ child.stdout.on('data', (data) => { console.log(`child stdout:\n${data}`); }); child.stderr.on('data', (data) => { console.error(`child stderr:\n${data}`); }); ~~~ 上述兩個處理器會輸出兩者的日志到主進程的`stdout`和`stderr`事件上。當我們執行前面的`spawn`函數時,`pwd`命令的輸出會被打印出來,并且子進程帶著代碼`0`退出,這表示沒有錯誤發生。 <br> 我們可以給命令傳遞參數,命令由`spawn`函數執行,`spawn`函數用上了第二個參數,這是一個傳遞給該命令的所有參數組成的數組。比如說,為了在當前目錄執行`find`命令,并帶上一個`-type f`參數(用于列出所有文件),我們可以這樣做: ~~~ const child = spawn('find', ['.', '-type', 'f']); ~~~ 如果這條命令的執行過程中出現錯誤,舉個例子,如果我們在 find 一個非法的目標文件,`child.stderr``data`事件處理器將會被觸發,`exit`事件處理器會報出一個退出代碼`1`,這標志著出現了錯誤。錯誤的值最終取決于宿主操作系統和錯誤類型。 <br> 子進程中的`stdin`是一個可寫流。我們可以用它給命令發送一些輸入。就跟所有的可寫流一樣,消費輸入最簡單的方式是使用`pipe`函數。我們可以簡單地將可讀流管道化到可寫流。既然主線程的`stdin`是一個可讀流,我們可以將其管道化到子進程的`stdin`流。舉個例子: ~~~ const { spawn } = require('child_process'); const child = spawn('wc'); process.stdin.pipe(child.stdin) child.stdout.on('data', (data) => { console.log(`child stdout:\n${data}`); }); ~~~ 在這個例子中,子進程調用`wc`命令,該命令可以統計 Linux 中的行數、單詞數和字符數。我們然后將主進程的`stdin`管道化到子進程的`stdin`(一個可寫流)。這個組合的結果是,我們得到了一個標準輸入模式,在這個模式下,我們可以輸入一些字符。當敲下`Ctrl+D`時,輸入的內容將會作為`wc`命令的輸入。 ![](https://box.kancloud.cn/9b13d3fbab6ee78bf6e80a0f42de715c_1000x562.png) 我們也可以將多個進程的標準輸入/輸出相互用管道連接,就像 Linux 命令那樣。比如說,我們可以管道化`find`命令的`stdout`到`wc`命令的`stdin`,這樣可以統計當前目錄的所有文件。 ~~~ const { spawn } = require('child_process'); const find = spawn('find', ['.', '-type', 'f']); const wc = spawn('wc', ['-l']); find.stdout.pipe(wc.stdin); wc.stdout.on('data', (data) => { console.log(`Number of files ${data}`); }); ~~~ 我給`wc`命令添加了`-l`參數,使它只統計行數。當執行完畢,上述代碼會輸出當前目錄下所有子目錄文件的行數。 <br> <br> # 創建子進程 * 下面列出來的都是異步創建子進程的方式,每一種方式都有對應的同步版本。 * `.exec()`、`.execFile()`、`.fork()`底層都是通過`.spawn()`實現的。 * `.exec()`、`execFile()`額外提供了回調,當子進程停止的時候執行。 ## child_process.exec(command[, options][, callback]) 創建一個shell,然后在shell里執行命令。執行完成后,將stdout、stderr作為參數傳入回調方法。 <br> options 參數說明: * cwd:當前工作路徑。 * env:環境變量。 * encoding:編碼,默認是utf8。 * shell:用來執行命令的shell,unix上默認是/bin/sh,windows上默認是cmd.exe。 * timeout:默認是0。如果timeout大于0,那么,當子進程運行超過timeout毫秒,那么,就會給進程發送killSignal指定的信號 * killSignal:默認是SIGTERM。 * uid:執行進程的uid。 * gid:執行進程的gid。 * maxBuffer:標準輸出、錯誤輸出最大允許的數據量(單位為字節),如果超出的話,子進程就會被殺死。默認是200*1024 ~~~ var exec = require('child_process').exec; // 解決windows命令編碼問題 https://ask.csdn.net/questions/167560 var iconv = require('iconv-lite'); var encoding = 'cp936'; var binaryEncoding = 'binary'; // 成功的例子 exec('dir', { encoding: binaryEncoding }, function (error, stdout, stderr) { if (error) { console.log(iconv.decode('error: ' + error, encoding)); return; } console.log(iconv.decode('stdout: ' + stdout, encoding)); console.log(iconv.decode('stderr: ' + typeof stderr, encoding)); }); // 失敗的例子 exec('ls hello.txt', { encoding: binaryEncoding }, function (error, stdout, stderr) { if (error) { console.log(iconv.decode('error: ' + error, encoding)); return; } console.log(iconv.decode('stdout: ' + stdout, encoding)); console.log(iconv.decode('stderr: ' + stderr, encoding)); }); ~~~ 備注: 1. 如果`timeout`大于0,那么,當子進程運行超過`timeout`毫秒,那么,就會給進程發送`killSignal`指定的信號(比如`SIGTERM`)。 2. 如果運行沒有出錯,那么`error`為`null`。如果運行出錯,那么,`error.code`就是退出代碼(exist code),`error.signal`會被設置成終止進程的信號。(比如`CTRL+C`時發送的`SIGINT`) ### 風險項 傳入的命令,如果是用戶輸入的,有可能產生類似sql注入的風險,比如 ~~~ exec('ls hello.txt; rm -rf *', function(error, stdout, stderr){ if(error) { console.error('error: ' + error); // return; } console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); }); ~~~ <br> ## child_process.execFile(file[, args][, options][, callback]) 跟`.exec()`類似,不同點在于,沒有創建一個新的shell。至少有兩點影響 1. 比`child_process.exec()`效率高一些。(實際待測試) 2. 一些操作,比如I/O重定向,文件glob等不支持。 > 如果你不想用 shell 執行一個文件,那么 execFile 函數正是你想要的。它的行為跟`exec`函數一模一樣,但沒有使用 shell,這會讓它更有效率。Windows 上,一些文件不能在它們自己之上執行,比如`.bat`或者`.cmd`文件。這些文件不能使用`execFile`執行,并且執行它們時,需要將 shell 設置為 true,且只能使用`exec`、`spawn`兩者之一。 `file`:可執行文件的名字,或者路徑。 ~~~ var child_process = require('child_process'); child_process.execFile('node', ['--version'], function(error, stdout, stderr){ if(error){ throw error; } console.log(stdout); }); child_process.execFile('/Users/a/.nvm/versions/node/v6.1.0/bin/node', ['--version'], function(error, stdout, stderr){ if(error){ throw error; } console.log(stdout); }); ~~~ 備注:execFile()內部最終還是通過spawn()實現的, 如果沒有設置 {shell: '/bin/bash'},那么 spawm() 內部對命令的解析會有所不同,execFile('ls -al .') 會直接報錯。 ~~~ var child_process = require('child_process'); var execFile = child_process.execFile; var exec = child_process.exec; exec('ls -al .', function(error, stdout, stderr){ if(error){ throw error; } console.log(stdout); }); execFile('ls -al .', {shell: '/bin/bash'}, function(error, stdout, stderr){ if(error){ throw error; } console.log(stdout); }); ~~~ <br> ## child_process.fork(modulePath[, args][, options]) `fork`函數是`spawn`函數針對衍生 node 進程的一個變種。`spawn`和`fork`最大的區別在于,使用`fork`時,通信頻道建立于子進程,因此我們可以在 fork 出來的進程上使用`send`函數,這些進程上有個全局`process`對象,可以用于父進程和 fork 進程之間傳遞消息。這個函數通過`EventEmitter`模塊接口實現。這里有個例子: 參數說明:(重復的參數說明就不在這里列舉) * `execPath`: 用來創建子進程的可執行文件,默認是`/usr/local/bin/node`。也就是說,你可通過`execPath`來指定具體的node可執行文件路徑。(比如多個node版本) * `execArgv`: 傳給可執行文件的字符串參數列表。默認是`process.execArgv`,跟父進程保持一致。 * `silent`: 默認是`false`,即子進程的`stdio`從父進程繼承。如果是`true`,則直接`pipe`向子進程的`child.stdin`、`child.stdout`等。 * `stdio`: 如果聲明了`stdio`,則會覆蓋`silent`選項的設置。 ### 例子一 這里有個 HTTP 服務器處理兩個端點。一個端點(下面的`/compute`)計算密集,會花好幾秒種完成。我們可以用一個長循環來模擬: ~~~ const http = require('http'); const longComputation = () => { let sum = 0; for (let i = 0; i < 1e9; i++) { sum += i; }; return sum; }; const server = http.createServer(); server.on('request', (req, res) => { if (req.url === '/compute') { const sum = longComputation(); return res.end(`Sum is ${sum}`); } else { res.end('Ok') } }); server.listen(3000); ~~~ 這段程序有個比較大的問題:當`/compute`端點被請求,服務器不能處理其他請求,因為長循環導致事件循環處于繁忙狀態。 這個問題有一些解決之道,這取決于耗時長運算的性質。但針對所有運算都適用的解決方法是,用`fork`將計算過程移動到另一個進程。 我們首先移動整個`longComputation`函數到它自己的文件,并在主進程通過消息發出通知時,在文件中調用這個函數: 一個新的`compute.js`文件中: ~~~ const longComputation = () => { let sum = 0; for (let i = 0; i < 1e9; i++) { sum += i; }; return sum; }; process.on('message', (msg) => { const sum = longComputation(); process.send(sum); }); ~~~ 現在,我們可以fork`compute.js`文件,并用消息接口實現服務器和復刻進程的消息通信,而不是在主進程事件循環中執行耗時操作。 ~~~ const http = require('http'); const { fork } = require('child_process'); const server = http.createServer(); server.on('request', (req, res) => { if (req.url === '/compute') { const compute = fork('compute.js'); compute.send('start'); compute.on('message', sum => { res.end(`Sum is ${sum}`); }); } else { res.end('Ok') } }); server.listen(3000); ~~~ 上面的代碼中,當`/compute`來了一個請求,我們可以簡單地發送一條消息給復刻進程,來啟動執行耗時運算。主進程的事件循環并不會阻塞。 一旦復刻進程執行完耗時操作,它可以用`process.send`將結果發回給父進程。 在父進程中,我們在 fork 的子進程本身上監聽`message`事件。當該事件觸發,我們會得到一個準備好的`sum`值,并通過 HTTP 發送給請求。 上面的代碼,當然,我們可以 fork 的進程數是有限的。但執行這段代碼時,HTTP 請求耗時運算的端點,主服務器根本不會阻塞,并且還可以接受更多的請求。 ### 例子二 **parent.js** ~~~ var child_process = require('child_process'); // 例子一:會打印出 output from the child // 默認情況,silent 為 false,子進程的 stdout 等 // 從父進程繼承 child_process.fork('./child.js', { silent: false }); // 例子二:不會打印出 output from the silent child // silent 為 true,子進程的 stdout 等 // pipe 向父進程 child_process.fork('./silentChild.js', { silent: true }); // 例子三:打印出 output from another silent child var child = child_process.fork('./anotherSilentChild.js', { silent: true }); child.stdout.setEncoding('utf8'); child.stdout.on('data', function(data){ console.log(data); });復制代碼 ~~~ **child.js** ~~~ console.log('output from the child');復制代碼 ~~~ **silentChild.js** ~~~ console.log('output from the silent child');復制代碼 ~~~ **anotherSilentChild.js** ~~~ console.log('output from another silent child');復制代碼 ~~~ <br> ### 例子三:ipc **parent.js** ~~~ var child_process = require('child_process'); var child = child_process.fork('./child.js'); child.on('message', function(m){ console.log('message from child: ' + JSON.stringify(m)); }); child.send({from: 'parent'});復制代碼 ~~~ **child.js** ~~~ process.on('message', function(m){ console.log('message from parent: ' + JSON.stringify(m)); }); process.send({from: 'child'});復制代碼 ~~~ 運行結果 ~~~ ? ipc git:(master) ? node parent.js message from child: {"from":"child"} message from parent: {"from":"parent"} ~~~ ### 例子四:execArgv 首先,process.execArgv的定義,參考[這里](https://link.juejin.im?target=https%3A%2F%2Fnodejs.org%2Fapi%2Fprocess.html%23process_process_execargv)。設置`execArgv`的目的一般在于,讓子進程跟父進程保持相同的執行環境。 比如,父進程指定了`--harmony`,如果子進程沒有指定,那么就要跪了。 parent.js ~~~ var child_process = require('child_process'); console.log('parent execArgv: ' + process.execArgv); child_process.fork('./child.js', { execArgv: process.execArgv });復制代碼 ~~~ child.js ~~~ console.log('child execArgv: ' + process.execArgv);復制代碼 ~~~ 運行結果 ~~~ ? execArgv git:(master) ? node --harmony parent.js parent execArgv: --harmony child execArgv: --harmony ~~~ ## child_process.spawn(command[, args][, options]) `command`:要執行的命令 options參數說明: * `argv0`:\[String\] 這貨比較詭異,在uninx、windows上表現不一樣。有需要再深究。 * `stdio`:\[Array\] | \[String\] 子進程的stdio。參考[這里](https://link.juejin.im?target=https%3A%2F%2Fnodejs.org%2Fapi%2Fchild_process.html%23child_process_options_stdio) * `detached`:\[Boolean\] 讓子進程獨立于父進程之外運行。同樣在不同平臺上表現有差異,具體參考[這里](https://link.juejin.im?target=https%3A%2F%2Fnodejs.org%2Fapi%2Fchild_process.html%23child_process_options_detached) * `shell`:\[Boolean\] | \[String\] 如果是`true`,在shell里運行程序。默認是`false`。(很有用,比如 可以通過 /bin/sh -c xxx 來實現 .exec() 這樣的效果) 例子1:基礎例子 ~~~ var spawn = require('child_process').spawn; var ls = spawn('ls', ['-al']); ls.stdout.on('data', function(data){ console.log('data from child: ' + data); }); ls.stderr.on('data', function(data){ console.log('error from child: ' + data); }); ls.on('close', function(code){ console.log('child exists with code: ' + code); });復制代碼 ~~~ 例子2:聲明stdio ~~~ var spawn = require('child_process').spawn; var ls = spawn('ls', ['-al'], { stdio: 'inherit' }); ls.on('close', function(code){ console.log('child exists with code: ' + code); });復制代碼 ~~~ 例子3:聲明使用shell ~~~ var spawn = require('child_process').spawn; // 運行 echo "hello nodejs" | wc var ls = spawn('bash', ['-c', 'echo "hello nodejs" | wc'], { stdio: 'inherit', shell: true }); ls.on('close', function(code){ console.log('child exists with code: ' + code); });復制代碼 ~~~ 例子4:錯誤處理,包含兩種場景,這兩種場景有不同的處理方式。 * 場景1:命令本身不存在,創建子進程報錯。 * 場景2:命令存在,但運行過程報錯。 ~~~ var spawn = require('child_process').spawn; var child = spawn('bad_command'); child.on('error', (err) => { console.log('Failed to start child process 1.'); }); var child2 = spawn('ls', ['nonexistFile']); child2.stderr.on('data', function(data){ console.log('Error msg from process 2: ' + data); }); child2.on('error', (err) => { console.log('Failed to start child process 2.'); });復制代碼 ~~~ 運行結果如下。 ~~~ ? spawn git:(master) ? node error/error.js Failed to start child process 1. Error msg from process 2: ls: nonexistFile: No such file or directory復制代碼 ~~~ 例子5:echo "hello nodejs" | grep "nodejs" ~~~ // echo "hello nodejs" | grep "nodejs" var child_process = require('child_process'); var echo = child_process.spawn('echo', ['hello nodejs']); var grep = child_process.spawn('grep', ['nodejs']); grep.stdout.setEncoding('utf8'); echo.stdout.on('data', function(data){ grep.stdin.write(data); }); echo.on('close', function(code){ if(code!==0){ console.log('echo exists with code: ' + code); } grep.stdin.end(); }); grep.stdout.on('data', function(data){ console.log('grep: ' + data); }); grep.on('close', function(code){ if(code!==0){ console.log('grep exists with code: ' + code); } });復制代碼 ~~~ 運行結果: ~~~ ? spawn git:(master) ? node pipe/pipe.js grep: hello nodejs復制代碼 ~~~ # 關于options.stdio 默認值:\['pipe', 'pipe', 'pipe'\],這意味著: 1. child.stdin、child.stdout 不是`undefined` 2. 可以通過監聽 `data` 事件,來獲取數據。 ## 基礎例子 ~~~ var spawn = require('child_process').spawn; var ls = spawn('ls', ['-al']); ls.stdout.on('data', function(data){ console.log('data from child: ' + data); }); ls.on('close', function(code){ console.log('child exists with code: ' + code); });復制代碼 ~~~ ## 通過child.stdin.write()寫入 ~~~ var spawn = require('child_process').spawn; var grep = spawn('grep', ['nodejs']); setTimeout(function(){ grep.stdin.write('hello nodejs \n hello javascript'); grep.stdin.end(); }, 2000); grep.stdout.on('data', function(data){ console.log('data from grep: ' + data); }); grep.on('close', function(code){ console.log('grep exists with code: ' + code); }); ~~~ <br> <br> # options.detached 在 Windows 上,設置 options.detached 為 true 可以使子進程在父進程退出后繼續運行。 子進程有自己的控制臺窗口。 一旦啟用一個子進程,它將不能被禁用。 <br> 在非 Windows 平臺上,如果 options.detached 設為 true,則子進程會成為新的進程組和會話的領導者。 子進程在父進程退出后可以繼續運行,不管它們是否被分離。 <br> 默認情況下,父進程會等待被分離的子進程退出。 為了防止父進程等待 subprocess,可以使用 subprocess.unref()。 這樣做會導致父進程的事件循環不包含子進程的引用計數,使得父進程獨立于子進程退出,除非子進程和父進程之間建立了一個 IPC 信道。 <br> 當使用 detached 選項來啟動一個長期運行的進程時,該進程不會在父進程退出后保持在后臺運行,除非指定一個不連接到父進程的 stdio 配置。 如果父進程的 stdio 是繼承的,則子進程會保持連接到控制終端。 <br> ## 默認情況:父進程等待子進程結束。 子進程。可以看到,有個定時器一直在跑 ~~~ var times = 0; setInterval(function(){ console.log(++times); }, 1000);復制代碼 ~~~ 運行下面代碼,會發現父進程一直hold著不退出。 ~~~ var child_process = require('child_process'); child_process.spawn('node', ['child.js'], { // stdio: 'inherit' }); ~~~ <br> ## 通過child.unref()讓父進程退出 調用`child.unref()`,將子進程從父進程的事件循環中剔除。于是父進程可以愉快的退出。這里有幾個要點 1. 調用`child.unref()` 2. 設置`detached`為`true` 3. 設置`stdio`為`ignore`(這點容易忘) ~~~ var child_process = require('child_process'); var child = child_process.spawn('node', ['child.js'], { detached: true, stdio: 'ignore' // 備注:如果不置為 ignore,那么 父進程還是不會退出 // stdio: 'inherit' }); child.unref();復制代碼 ~~~ ## 將`stdio`重定向到文件 除了直接將stdio設置為`ignore`,還可以將它重定向到本地的文件。 ~~~ var child_process = require('child_process'); var fs = require('fs'); var out = fs.openSync('./out.log', 'a'); var err = fs.openSync('./err.log', 'a'); var child = child_process.spawn('node', ['child.js'], { detached: true, stdio: ['ignore', out, err] }); child.unref(); ~~~ <br> <br> # 在 Windows 上衍生`.bat`和`.cmd`文件 [`child_process.exec()`](http://nodejs.cn/s/pkpJMy)和[`child_process.execFile()`](http://nodejs.cn/s/N6uK8q)之間的重要區別可能因平臺而異。 在 Unix 類型的操作系統(Unix、Linux、macOS)上,[`child_process.execFile()`](http://nodejs.cn/s/N6uK8q)可以更高效,因為默認情況下它不會衍生 shell。 但是在 Windows 上,`.bat`和`.cmd`文件在沒有終端的情況下不能自行執行,因此無法使用[`child_process.execFile()`](http://nodejs.cn/s/N6uK8q)啟動。 在 Windows 上運行時,可以使用帶有`shell`選項集的[`child_process.spawn()`](http://nodejs.cn/s/CKoDGf)、或使用[`child_process.exec()`](http://nodejs.cn/s/pkpJMy)或通過衍生`cmd.exe`并將`.bat`或`.cmd`文件作為參數傳入(也就是`shell`選項和[`child_process.exec()`](http://nodejs.cn/s/pkpJMy)所做的)。 在任何情況下,如果腳本文件名包含空格,則需要加上引號。 ~~~js // 僅限 Windows 系統。 const { spawn } = require('child_process'); const bat = spawn('cmd.exe', ['/c', 'my.bat']); bat.stdout.on('data', (data) => { console.log(data.toString()); }); bat.stderr.on('data', (data) => { console.log(data.toString()); }); bat.on('exit', (code) => { console.log(`子進程退出碼:${code}`); }); ~~~ ~~~js // 或: const { exec } = require('child_process'); exec('my.bat', (err, stdout, stderr) => { if (err) { console.error(err); return; } console.log(stdout); }); // 文件名中包含空格的腳本: const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true }); // 或: exec('"my script.cmd" a b', (err, stdout, stderr) => { // ... }); ~~~ # 代碼運行次序的問題 **p.js** ~~~ const cp = require('child_process'); const n = cp.fork(`${__dirname}/sub.js`); console.log('1'); n.on('message', (m) => { console.log('PARENT got message:', m); }); console.log('2'); n.send({ hello: 'world' }); console.log('3'); ~~~ **sub.js** ~~~ console.log('4'); process.on('message', (m) => { console.log('CHILD got message:', m); }); process.send({ foo: 'bar' }); console.log('5');復制代碼 ~~~ 運行`node p.js`,打印出來的內容如下 ~~~ ? ch node p.js 1 2 3 4 5 PARENT got message: { foo: 'bar' } CHILD got message: { hello: 'world' }復制代碼 ~~~ 再來個例子 ~~~ // p2.js var fork = require('child_process').fork; console.log('p: 1'); fork('./c2.js'); console.log('p: 2'); // 從測試結果來看,同樣是70ms,有的時候,定時器回調比子進程先執行,有的時候比子進程慢執行。 const t = 70; setTimeout(function(){ console.log('p: 3 in %s', t); }, t); // c2.js console.log('c: 1'); ~~~ <br> # 參考資料 [Nodejs進階:如何玩轉子進程(child\_process)](https://juejin.im/post/5848ee3c8e450a006aad306b) [Node.js 子進程:你應該知道的一切](https://github.com/xitu/gold-miner/blob/master/TODO/node-js-child-processes-everything-you-need-to-know.md) [深入理解Node.js 中的進程與線程](https://juejin.im/post/5d43017be51d4561f40adcf9) [Nodejs cluster模塊深入探究](https://segmentfault.com/a/1190000010260600) [nodejs中的子進程,深入解析child_process模塊和cluster模塊](https://segmentfault.com/a/1190000016169207)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看