久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      一文聊聊Node.js中的進(jìn)程與子進(jìn)程

      本篇文章帶大家深入了解下Node中的進(jìn)程與子進(jìn)程,希望對大家有所幫助!

      一文聊聊Node.js中的進(jìn)程與子進(jìn)程

      node.js極速入門課程:進(jìn)入學(xué)習(xí)

      進(jìn)程:process模塊

      process 模塊是 nodejs 提供給開發(fā)者用來和當(dāng)前進(jìn)程交互的工具,它的提供了很多實用的 API?!鞠嚓P(guān)教程推薦:nodejs視頻教程】

      從文檔出發(fā),管中窺豹,進(jìn)一步認(rèn)識和學(xué)習(xí) process 模塊:

      • 如何處理命令參數(shù)?
      • 如何處理工作目錄?
      • 如何處理異常?
      • 如何處理進(jìn)程退出?
      • process 的標(biāo)準(zhǔn)流對象
      • 深入理解 process.nextTick

      如何處理命令參數(shù)?

      命令行參數(shù)指的是 2 個方面:

      • 傳給 node 的參數(shù)。例如 node --harmony script.js --version 中,--harmony 就是傳給 node 的參數(shù)
      • 傳給進(jìn)程的參數(shù)。例如 node script.js --version --help 中,--version --help 就是傳給進(jìn)程的參數(shù)

      它們分別通過 process.argvprocess.execArgv 來獲得。

      如何處理工作目錄?

      通過process.cwd()可以獲取當(dāng)前的工作目錄。

      通過process.chdir(directory)可以切換當(dāng)前的工作目錄,失敗后會拋出異常。實踐如下:

      function safeChdir(dir) {     try {         process.chdir(dir);         return true;     } catch (error) {         return false;     } }
      登錄后復(fù)制

      如何處理異常?

      uncaughtException 事件

      Nodejs 可以通過 try-catch 來捕獲異常。如果異常未捕獲,則會一直從底向事件循環(huán)冒泡。如是冒泡到事件循環(huán)的異常沒被處理,那么就會導(dǎo)致當(dāng)前進(jìn)程異常退出。

      根據(jù)文檔,可以通過監(jiān)聽 process 的 uncaughtException 事件,來處理未捕獲的異常:

      process.on("uncaughtException", (err, origin) => {     console.log(err.message); });  const a = 1 / b; console.log("abc"); // 不會執(zhí)行
      登錄后復(fù)制

      上面的代碼,控制臺的輸出是:b is not defined。捕獲了錯誤信息,并且進(jìn)程以0退出。開發(fā)者可以在 uncaughtException 事件中,清除一些已經(jīng)分配的資源(文件描述符、句柄等),不推薦在其中重啟進(jìn)程。

      unhandledRejection 事件

      如果一個 Promise 回調(diào)的異常沒有被.catch()捕獲,那么就會觸發(fā) process 的 unhandledRejection 事件:

      process.on("unhandledRejection", (err, promise) => {     console.log(err.message); });  Promise.reject(new Error("錯誤信息")); // 未被catch捕獲的異常,交由unhandledRejection事件處理
      登錄后復(fù)制

      warning 事件

      告警不是 Node.js 和 Javascript 錯誤處理流程的正式組成部分。 一旦探測到可能導(dǎo)致應(yīng)用性能問題,缺陷或安全隱患相關(guān)的代碼實踐,Node.js 就可發(fā)出告警。

      比如前一段代碼中,如果出現(xiàn)未被捕獲的 promise 回調(diào)的異常,那么就會觸發(fā) warning 事件。參考nodejs進(jìn)階視頻講解:進(jìn)入學(xué)習(xí)

      如何處理進(jìn)程退出?

      process.exit() vs process.exitCode

      一個 nodejs 進(jìn)程,可以通過 process.exit() 來指定退出代碼,直接退出。不推薦直接使用 process.exit(),這會導(dǎo)致事件循環(huán)中的任務(wù)直接不被處理,以及可能導(dǎo)致數(shù)據(jù)的截斷和丟失(例如 stdout 的寫入)。

      setTimeout(() => {     console.log("我不會執(zhí)行"); });  process.exit(0);
      登錄后復(fù)制

      正確安全的處理是,設(shè)置 process.exitCode,并允許進(jìn)程自然退出。

      setTimeout(() => {     console.log("我不會執(zhí)行"); });  process.exitCode = 1;
      登錄后復(fù)制

      beforeExit 事件

      用于處理進(jìn)程退出的事件有:beforeExit 事件 和 exit 事件。

      當(dāng) Node.js 清空其事件循環(huán)并且沒有其他工作要安排時,會觸發(fā) beforeExit 事件。例如在退出前需要一些異步操作,那么可以寫在 beforeExit 事件中:

      let hasSend = false; process.on("beforeExit", () => {     if (hasSend) return; // 避免死循環(huán)      setTimeout(() => {         console.log("mock send data to serve");         hasSend = true;     }, 500); });  console.log("......."); // 輸出: // ....... // mock send data to serve
      登錄后復(fù)制

      注意:在 beforeExit 事件中如果是異步任務(wù),那么又會被添加到任務(wù)隊列。此時,任務(wù)隊列完成所有任務(wù)后,又回觸發(fā) beforeExit 事件。因此,不處理的話,可能出現(xiàn)死循環(huán)的情況。如果是顯式調(diào)用 exit(),那么不會觸發(fā)此事件。

      exit 事件

      在 exit 事件中,只能執(zhí)行同步操作。在調(diào)用 'exit' 事件監(jiān)聽器之后,Node.js 進(jìn)程將立即退出,從而導(dǎo)致在事件循環(huán)中仍排隊的任何其他工作被放棄。

      process 的標(biāo)準(zhǔn)流對象

      process 提供了 3 個標(biāo)準(zhǔn)流。需要注意的是,它們有些在某些時候是同步阻塞的(請見文檔)。

      • process.stderr:WriteStream 類型,console.error的底層實現(xiàn),默認(rèn)對應(yīng)屏幕
      • process.stdout:WriteStream 類型,console.log的底層實現(xiàn),默認(rèn)對應(yīng)屏幕
      • process.stdin:ReadStream 類型,默認(rèn)對應(yīng)鍵盤輸入

      下面是基于“生產(chǎn)者-消費者模型”的讀取控制臺輸入并且及時輸出的代碼:

      process.stdin.setEncoding("utf8");  process.stdin.on("readable", () => {     let chunk;     while ((chunk = process.stdin.read()) !== null) {         process.stdout.write(`>>> ${chunk}`);     } });  process.stdin.on("end", () => {     process.stdout.write("結(jié)束"); });
      登錄后復(fù)制

      關(guān)于事件的含義,還是請看stream 的文檔。

      深入理解 process.nextTick

      我第一次看到 process.nextTick 的時候是比較懵的,看文檔可以知道,它的用途是:把回調(diào)函數(shù)作為微任務(wù),放入事件循環(huán)的任務(wù)隊列中。但這么做的意義是什么呢?

      因為 nodejs 并不適合計算密集型的應(yīng)用,一個進(jìn)程就一個線程,在當(dāng)下時間點上,就一個事件在執(zhí)行。那么,如果我們的事件占用了很多 cpu 時間,那么之后的事件就要等待非常久。所以,nodejs 的一個編程原則是盡量縮短每一個事件的執(zhí)行事件。process.nextTick 的作用就在這,將一個大的任務(wù)分解成多個小的任務(wù)。示例代碼如下:

      // 被拆分成2個函數(shù)執(zhí)行 function BigThing() {     doPartThing();      process.nextTick(() => finishThing()); }
      登錄后復(fù)制

      在事件循環(huán)中,何時執(zhí)行 nextTick 注冊的任務(wù)呢?請看下面的代碼:

      setTimeout(function() {     console.log("第一個1秒");     process.nextTick(function() {         console.log("第一個1秒:nextTick");     }); }, 1000);  setTimeout(function() {     console.log("第2個1秒"); }, 1000);  console.log("我要輸出1");  process.nextTick(function() {     console.log("nextTick"); });  console.log("我要輸出2");
      登錄后復(fù)制

      輸出的結(jié)果如下,nextTick 是早于 setTimeout:

      我要輸出1 我要輸出2 nextTick 第一個1秒 第一個1秒:nextTick 第2個1秒
      登錄后復(fù)制

      在瀏覽器端,nextTick 會退化成 setTimeout(callback, 0)。但在 nodejs 中請使用 nextTick 而不是 setTimeout,前者效率更高,并且嚴(yán)格來說,兩者創(chuàng)建的事件在任務(wù)隊列中順序并不一樣(請看前面的代碼)。

      子進(jìn)程:child_process模塊

      掌握 nodejs 的 child_process 模塊能夠極大提高 nodejs 的開發(fā)能力,例如主從進(jìn)程來優(yōu)化 CPU 計算的問題,多進(jìn)程開發(fā)等等。本文從以下幾個方面介紹 child_process 模塊的使用:

      • 創(chuàng)建子進(jìn)程
      • 父子進(jìn)程通信
      • 獨立子進(jìn)程
      • 進(jìn)程管道

      創(chuàng)建子進(jìn)程

      nodejs 的 child_process 模塊創(chuàng)建子進(jìn)程的方法:spawn, fork, exec, execFile。它們的關(guān)系如下:

      • fork, exec, execFile 都是通過 spawn 來實現(xiàn)的。
      • exec 默認(rèn)會創(chuàng)建 shell。execFile 默認(rèn)不會創(chuàng)建 shell,意味著不能使用 I/O 重定向、file glob,但效率更高。
      • spawn、exec、execFile 都有同步版本,可能會造成進(jìn)程阻塞。

      child_process.spawn()的使用:

      const { spawn } = require("child_process"); // 返回ChildProcess對象,默認(rèn)情況下其上的stdio不為null const ls = spawn("ls", ["-lh"]);  ls.stdout.on("data", data => {     console.log(`stdout: ${data}`); });  ls.stderr.on("data", data => {     console.error(`stderr: ${data}`); });  ls.on("close", code => {     console.log(`子進(jìn)程退出,退出碼 ${code}`); });
      登錄后復(fù)制

      child_process.exec()的使用:

      const { exec } = require("child_process"); // 通過回調(diào)函數(shù)來操作stdio exec("ls -lh", (err, stdout, stderr) => {     if (err) {         console.error(`執(zhí)行的錯誤: ${err}`);         return;     }     console.log(`stdout: ${stdout}`);     console.error(`stderr: ${stderr}`); });
      登錄后復(fù)制

      父子進(jìn)程通信

      fork()返回的 ChildProcess 對象,監(jiān)聽其上的 message 事件,來接受子進(jìn)程消息;調(diào)用 send 方法,來實現(xiàn) IPC。

      parent.js 代碼如下:

      const { fork } = require("child_process"); const cp = fork("./sub.js"); cp.on("message", msg => {     console.log("父進(jìn)程收到消息:", msg); }); cp.send("我是父進(jìn)程");
      登錄后復(fù)制

      sub.js 代碼如下:

      process.on("message", m => {     console.log("子進(jìn)程收到消息:", m); });  process.send("我是子進(jìn)程");
      登錄后復(fù)制

      運行后結(jié)果:

      父進(jìn)程收到消息: 我是子進(jìn)程 子進(jìn)程收到消息: 我是父進(jìn)程
      登錄后復(fù)制

      獨立子進(jìn)程

      在正常情況下,父進(jìn)程一定會等待子進(jìn)程退出后,才退出。如果想讓父進(jìn)程先退出,不受到子進(jìn)程的影響,那么應(yīng)該:

      • 調(diào)用 ChildProcess 對象上的unref()
      • options.detached 設(shè)置為 true
      • 子進(jìn)程的 stdio 不能是連接到父進(jìn)程

      main.js 代碼如下:

      const { spawn } = require("child_process"); const subprocess = spawn(process.argv0, ["sub.js"], {     detached: true,     stdio: "ignore" });  subprocess.unref();
      登錄后復(fù)制

      sub.js 代碼如下:

      setInterval(() => {}, 1000);
      登錄后復(fù)制

      進(jìn)程管道

      options.stdio 選項用于配置在父進(jìn)程和子進(jìn)程之間建立的管道。 默認(rèn)情況下,子進(jìn)程的 stdin、 stdout 和 stderr 會被重定向到 ChildProcess 對象上相應(yīng)的 subprocess.stdin、subprocess.stdout 和 subprocess.stderr 流。 這意味著可以通過監(jiān)聽其上的 data事件,在父進(jìn)程中獲取子進(jìn)程的 I/O 。

      可以用來實現(xiàn)“重定向”:

      const fs = require("fs"); const child_process = require("child_process");  const subprocess = child_process.spawn("ls", {     stdio: [         0, // 使用父進(jìn)程的 stdin 用于子進(jìn)程。         "pipe", // 把子進(jìn)程的 stdout 通過管道傳到父進(jìn)程 。         fs.openSync("err.out", "w") // 把子進(jìn)程的 stderr 定向到一個文件。     ] });
      登錄后復(fù)制

      也可以用來實現(xiàn)"管道運算符":

      const { spawn } = require("child_process");  const ps = spawn("ps", ["ax"]); const grep = spawn("grep", ["ssh"]);  ps.stdout.on("data", data => {     grep.stdin.write(data); });  ps.stderr.on("data", err => {     console.error(`ps stderr: ${err}`); });  ps.on("close", code => {     if (code !== 0) {         console.log(`ps 進(jìn)程退出,退出碼 ${code}`);     }     grep.stdin.end(); });  grep.stdout.on("data", data => {     console.log(data.toString()); });  grep.stderr.on("data", data => {     console.error(`grep stderr: ${data}`); });  grep.on("close", code => {     if (code !== 0) {         console.log(`grep 進(jìn)程退出,退出碼 ${code}`);     } });
      登錄后復(fù)制

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號