国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

通過源碼解析 Node.js 啟動時(shí)第一個執(zhí)行的 js 文件:bootstrap_node.js

TNFE / 3466人閱讀

摘要:注很多以前的源碼分析文章中,所寫的第一個執(zhí)行的文件代碼為,但這個文件在中已被移除,并被拆解為了等其他下的文件,為正文作為第一段被執(zhí)行的代碼,它的歷史使命免不了就是進(jìn)行一些環(huán)境和全局變量的初始化工作。

大家可能會好奇,在 Node.js 啟動后,第一個執(zhí)行的 JavaScript 文件會是哪個?它具體又會干些什么事?

一步步來看,翻開 Node.js 的源碼,不難看出,入口文件在 src/node_main.cc 中,主要任務(wù)為將參數(shù)傳入 node::Start 函數(shù):

</>復(fù)制代碼

  1. // src/node_main.cc
  2. // ...
  3. int main(int argc, char *argv[]) {
  4. setvbuf(stderr, NULL, _IOLBF, 1024);
  5. return node::Start(argc, argv);
  6. }

node::Start 函數(shù)定義于 src/node.cc 中,它進(jìn)行了必要的初始化工作后,會調(diào)用 StartNodeInstance

</>復(fù)制代碼

  1. // src/node.cc
  2. // ...
  3. int Start(int argc, char** argv) {
  4. // ...
  5. NodeInstanceData instance_data(NodeInstanceType::MAIN,
  6. uv_default_loop(),
  7. argc,
  8. const_cast(argv),
  9. exec_argc,
  10. exec_argv,
  11. use_debug_agent);
  12. StartNodeInstance(&instance_data);
  13. }

而在 StartNodeInstance 函數(shù)中,又調(diào)用了 LoadEnvironment 函數(shù),其中的 ExecuteString(env, MainSource(env), script_name); 步驟,便執(zhí)行了第一個 JavaScript 文件代碼:

</>復(fù)制代碼

  1. // src/node.cc
  2. // ...
  3. void LoadEnvironment(Environment* env) {
  4. // ...
  5. Local f_value = ExecuteString(env, MainSource(env), script_name);
  6. // ...
  7. }
  8. static void StartNodeInstance(void* arg) {
  9. // ...
  10. {
  11. Environment::AsyncCallbackScope callback_scope(env);
  12. LoadEnvironment(env);
  13. }
  14. // ...
  15. }
  16. // src/node_javascript.cc
  17. // ...
  18. Local MainSource(Environment* env) {
  19. return String::NewFromUtf8(
  20. env->isolate(),
  21. reinterpret_cast(internal_bootstrap_node_native),
  22. NewStringType::kNormal,
  23. sizeof(internal_bootstrap_node_native)).ToLocalChecked();
  24. }

其中的 internal_bootstrap_node_native ,即為 lib/internal/bootstrap_node.js 中的代碼。(注:很多以前的 Node.js 源碼分析文章中,所寫的第一個執(zhí)行的 JavaScript 文件代碼為 src/node.js ,但這個文件在 Node.js v5.10 中已被移除,并被拆解為了 lib/internal/bootstrap_node.js 等其他 lib/internal 下的文件,PR 為: https://github.com/nodejs/node/pull/5103 )

正文

作為第一段被執(zhí)行的 JavaScript 代碼,它的歷史使命免不了就是進(jìn)行一些環(huán)境和全局變量的初始化工作。代碼的整體結(jié)構(gòu)很簡單,所有的初始化邏輯都被封裝在了 startup 函數(shù)中:

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. // ...
  6. }
  7. // ...
  8. startup();
  9. });

而在 startup 函數(shù)中,邏輯可以分為四塊:

初始化全局 process 對象上的部分屬性 / 行為

初始化全局的一些 timer 方法

初始化全局 console 等對象

開始執(zhí)行用戶執(zhí)行指定的 JavaScript 代碼

讓我們一個個來解析。

初始化全局 process 對象上的部分屬性 / 行為 添加 processuncaughtException 事件的默認(rèn)行為

在 Node.js 中,如果沒有為 process 上的 uncaughtException 事件注冊監(jiān)聽器,那么該事件觸發(fā)時(shí),將會導(dǎo)致進(jìn)程退出,這個行為便是在 startup 函數(shù)里添加的:

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. setupProcessFatal();
  6. }
  7. // ...
  8. function setupProcessFatal() {
  9. process._fatalException = function(er) {
  10. var caught;
  11. // ...
  12. if (!caught)
  13. caught = process.emit("uncaughtException", er);
  14. if (!caught) {
  15. try {
  16. if (!process._exiting) {
  17. process._exiting = true;
  18. process.emit("exit", 1);
  19. }
  20. } catch (er) {
  21. }
  22. }
  23. // ...
  24. return caught;
  25. };
  26. }
  27. });

邏輯十分直白,使用到了 EventEmitter#emit 的返回值來判斷該事件上是否有注冊過的監(jiān)聽器,并最終調(diào)用 c++ 的 exit() 函數(shù)退出進(jìn)程:

</>復(fù)制代碼

  1. // src/node.cc
  2. // ...
  3. void FatalException(Isolate* isolate,
  4. Local error,
  5. Local message) {
  6. // ...
  7. Local caught =
  8. fatal_exception_function->Call(process_object, 1, &error);
  9. // ...
  10. if (false == caught->BooleanValue()) {
  11. ReportException(env, error, message);
  12. exit(1);
  13. }
  14. }
根據(jù) Node.js 在啟動時(shí)所帶的某些參數(shù),來調(diào)整 processwarning 事件觸發(fā)時(shí)的行為

具體來說,這些參數(shù)是:--no-warnings,--no-deprecation--trace-deprecation--throw-deprecation。這些參數(shù)的有無信息,會先被掛載在 process 對象上:

</>復(fù)制代碼

  1. // src/node.cc
  2. // ...
  3. if (no_deprecation) {
  4. READONLY_PROPERTY(process, "noDeprecation", True(env->isolate()));
  5. }
  6. if (no_process_warnings) {
  7. READONLY_PROPERTY(process, "noProcessWarnings", True(env->isolate()));
  8. }
  9. if (trace_warnings) {
  10. READONLY_PROPERTY(process, "traceProcessWarnings", True(env->isolate()));
  11. }
  12. if (throw_deprecation) {
  13. READONLY_PROPERTY(process, "throwDeprecation", True(env->isolate()));
  14. }

然后根據(jù)這些信息,控制行為:

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. // ...
  6. NativeModule.require("internal/process/warning").setup();
  7. }
  8. // ...
  9. startup();
  10. });

</>復(fù)制代碼

  1. // lib/internal/process/warning.js
  2. "use strict";
  3. const traceWarnings = process.traceProcessWarnings;
  4. const noDeprecation = process.noDeprecation;
  5. const traceDeprecation = process.traceDeprecation;
  6. const throwDeprecation = process.throwDeprecation;
  7. const prefix = `(${process.release.name}:${process.pid}) `;
  8. exports.setup = setupProcessWarnings;
  9. function setupProcessWarnings() {
  10. if (!process.noProcessWarnings) {
  11. process.on("warning", (warning) => {
  12. if (!(warning instanceof Error)) return;
  13. const isDeprecation = warning.name === "DeprecationWarning";
  14. if (isDeprecation && noDeprecation) return;
  15. const trace = traceWarnings || (isDeprecation && traceDeprecation);
  16. if (trace && warning.stack) {
  17. console.error(`${prefix}${warning.stack}`);
  18. } else {
  19. var toString = warning.toString;
  20. if (typeof toString !== "function")
  21. toString = Error.prototype.toString;
  22. console.error(`${prefix}${toString.apply(warning)}`);
  23. }
  24. });
  25. }
  26. // ...
  27. }

具體行為的話,文檔中已經(jīng)有詳細(xì)說明,邏輯總結(jié)來說,就是按需將警告打印到控制臺,或者按需拋出特定的異常。其中 NativeModule 對象為 Node.js 在當(dāng)前的函數(shù)體的局部作用域內(nèi),實(shí)現(xiàn)的一個最小可用的模塊加載器,具有緩存等基本功能。

process 添加上 stdin, stdoutstderr 屬性

通常為 tty.ReadStream 類和 tty.WriteStream 類的實(shí)例:

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. // ...
  6. NativeModule.require("internal/process/stdio").setup();
  7. }
  8. // ...
  9. startup();
  10. });

</>復(fù)制代碼

  1. // lib/internal/process/stdio.js
  2. // ...
  3. function setupStdio() {
  4. var stdin, stdout, stderr;
  5. process.__defineGetter__("stdout", function() {
  6. if (stdout) return stdout;
  7. stdout = createWritableStdioStream(1);
  8. // ...
  9. return stdout
  10. }
  11. process.__defineGetter__("stderr", function() {
  12. if (stderr) return stderr;
  13. stderr = createWritableStdioStream(2);
  14. // ...
  15. return stderr;
  16. });
  17. process.__defineGetter__("stdin", function() {
  18. if (stdin) return stdin;
  19. var tty_wrap = process.binding("tty_wrap");
  20. var fd = 0;
  21. switch (tty_wrap.guessHandleType(fd)) {
  22. case "TTY":
  23. var tty = require("tty");
  24. stdin = new tty.ReadStream(fd, {
  25. highWaterMark: 0,
  26. readable: true,
  27. writable: false
  28. });
  29. break;
  30. // ...
  31. }
  32. return stdin;
  33. }
  34. }
  35. function createWritableStdioStream(fd) {
  36. var stream;
  37. var tty_wrap = process.binding("tty_wrap");
  38. // Note stream._type is used for test-module-load-list.js
  39. switch (tty_wrap.guessHandleType(fd)) {
  40. case "TTY":
  41. var tty = require("tty");
  42. stream = new tty.WriteStream(fd);
  43. stream._type = "tty";
  44. break;
  45. // ...
  46. }
  47. // ...
  48. }
process 添加上 nextTick 方法

具體的做法便是將注冊的回調(diào)推進(jìn)隊(duì)列中,等待事件循環(huán)的下一次 Tick ,一個個取出執(zhí)行:

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. // ...
  6. NativeModule.require("internal/process/next_tick").setup();
  7. }
  8. // ...
  9. startup();
  10. });

</>復(fù)制代碼

  1. // lib/internal/process/next_tick.js
  2. "use strict";
  3. exports.setup = setupNextTick;
  4. function setupNextTick() {
  5. var nextTickQueue = [];
  6. // ...
  7. var kIndex = 0;
  8. var kLength = 1;
  9. process.nextTick = nextTick;
  10. process._tickCallback = _tickCallback;
  11. function _tickCallback() {
  12. var callback, args, tock;
  13. do {
  14. while (tickInfo[kIndex] < tickInfo[kLength]) {
  15. tock = nextTickQueue[tickInfo[kIndex]++];
  16. callback = tock.callback;
  17. args = tock.args;
  18. _combinedTickCallback(args, callback);
  19. if (1e4 < tickInfo[kIndex])
  20. tickDone();
  21. }
  22. tickDone();
  23. } while (tickInfo[kLength] !== 0);
  24. }
  25. function nextTick(callback) {
  26. if (typeof callback !== "function")
  27. throw new TypeError("callback is not a function");
  28. if (process._exiting)
  29. return;
  30. var args;
  31. if (arguments.length > 1) {
  32. args = new Array(arguments.length - 1);
  33. for (var i = 1; i < arguments.length; i++)
  34. args[i - 1] = arguments[i];
  35. }
  36. nextTickQueue.push(new TickObject(callback, args));
  37. tickInfo[kLength]++;
  38. }
  39. }
  40. // ...
process 添加上 hrtime, kill, exit 方法

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. // ...
  6. _process.setup_hrtime();
  7. _process.setupKillAndExit();
  8. }
  9. // ...
  10. startup();
  11. });

這些功能的核心實(shí)現(xiàn)也重度依賴于 c++ 函數(shù):

hrtime 方法依賴于 libuv 提供的 uv_hrtime() 函數(shù)

kill 方法依賴于 libuv 提供的 uv_kill(pid, sig) 函數(shù)

exit 方法依賴于 c++ 提供的 exit(code) 函數(shù)

初始化全局的一些 timer 方法和 console 等對象

這些初始化都干的十分簡單,直接賦值:

</>復(fù)制代碼

  1. // lib/internal/bootstrap_node.js
  2. "use strict";
  3. (function(process) {
  4. function startup() {
  5. // ...
  6. setupGlobalVariables();
  7. if (!process._noBrowserGlobals) {
  8. setupGlobalTimeouts();
  9. setupGlobalConsole();
  10. }
  11. function setupGlobalVariables() {
  12. global.process = process;
  13. // ...
  14. global.Buffer = NativeModule.require("buffer").Buffer;
  15. process.domain = null;
  16. process._exiting = false;
  17. }
  18. function setupGlobalTimeouts() {
  19. const timers = NativeModule.require("timers");
  20. global.clearImmediate = timers.clearImmediate;
  21. global.clearInterval = timers.clearInterval;
  22. global.clearTimeout = timers.clearTimeout;
  23. global.setImmediate = timers.setImmediate;
  24. global.setInterval = timers.setInterval;
  25. global.setTimeout = timers.setTimeout;
  26. }
  27. function setupGlobalConsole() {
  28. global.__defineGetter__("console", function() {
  29. return NativeModule.require("console");
  30. });
  31. }
  32. }
  33. // ...
  34. startup();
  35. });

值得注意的一點(diǎn)是,由于 console 是通過 __defineGetter__ 賦值給 global 對象的,所以在嚴(yán)格模式下給它賦值將會拋出異常,而非嚴(yán)格模式下,賦值將被忽略。

開始執(zhí)行用戶執(zhí)行指定的 JavaScript 代碼

這一部分的邏輯已經(jīng)在之前的文章中有所闡述,這邊就不再重復(fù)說明啦。

最后

還是再次總結(jié)下:

lib/internal/bootstrap_node.js 中的代碼 為 Node.js 執(zhí)行后第一段被執(zhí)行的 JavaScript 代碼,從 src/node.cc 中的 node::LoadEnvironment 被調(diào)用

lib/internal/bootstrap_node.js 主要進(jìn)行了一些初始化工作:

初始化全局 process 對象上的部分屬性 / 行為

添加接收到 uncaughtException 事件時(shí)的默認(rèn)行為

根據(jù) Node.js 啟動時(shí)參數(shù),調(diào)整 warning 事件的行為

添加上 stdin,stdoutstderr 屬性

添加上 nextTick,hrtime,exit 方法

初始化全局的一些 timer 方法

初始化全局 console 等對象

開始執(zhí)行用戶執(zhí)行指定的 JavaScript 代碼

參考

https://github.com/nodejs/node/blob/master/src/node.cc

https://github.com/nodejs/node/blob/master/src/node_javascript.cc

https://github.com/nodejs/node/blob/master/lib/internal/process.js

https://github.com/nodejs/node/blob/master/lib/internal/process/next_tick.js

https://github.com/nodejs/node/blob/master/lib/internal/process/stdio.js

https://github.com/nodejs/node/blob/master/lib/internal/process/warning.js

https://github.com/nodejs/node/blob/master/lib/internal/bootstrap_node.js

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79329.html

相關(guān)文章

  • 干貨 | 走進(jìn)Node.js啟動過程剖析

    摘要:具體調(diào)用鏈路如圖函數(shù)主要是解析啟動參數(shù),并過濾選項(xiàng)傳給引擎。查閱文檔之后發(fā)現(xiàn),通過指定參數(shù)可以設(shè)置線程池大小。原來的字節(jié)碼編譯優(yōu)化還有都是通過多線程完成又繼續(xù)深入調(diào)查,發(fā)現(xiàn)環(huán)境變量會影響的線程池大小。執(zhí)行過程如下調(diào)用執(zhí)行。 作者:正龍 (滬江Web前端開發(fā)工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處。 隨著Node.js的普及,越來越多的開發(fā)者使用Node.js來搭建環(huán)境,也有很多公司開始把...

    luck 評論0 收藏0
  • 干貨剖析 | 走進(jìn)Node.js啟動過程

    摘要:具體調(diào)用鏈路如圖函數(shù)主要是解析啟動參數(shù),并過濾選項(xiàng)傳給引擎。查閱文檔之后發(fā)現(xiàn),通過指定參數(shù)可以設(shè)置線程池大小。原來的字節(jié)碼編譯優(yōu)化還有都是通過多線程完成又繼續(xù)深入調(diào)查,發(fā)現(xiàn)環(huán)境變量會影響的線程池大小。執(zhí)行過程如下調(diào)用執(zhí)行。 作者:正龍 (滬江Web前端開發(fā)工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處。 隨著Node.js的普及,越來越多的開發(fā)者使用Node.js來搭建環(huán)境,也有很多公司開始把...

    Simon 評論0 收藏0
  • nodejs源碼require問題

    摘要:提起中的模塊,就會想到用去加在引用那個模塊??戳瞬簧俨┛?,加載機(jī)制明白了,腦子里總是稀里糊涂的知道會每個文件會被文件的源碼包裹,自然也就有文件中的命令了。于是想寫寫記錄自己的整個過程。這就是幾個的關(guān)系。 提起nodejs中的模塊,就會想到用require去加在引用那個模塊??戳瞬簧俨┛?,加載機(jī)制明白了,腦子里總是稀里糊涂的知道會每個文件會被(function (exports, req...

    LiveVideoStack 評論0 收藏0
  • JavaScript中遞歸

    摘要:第三次第四次設(shè)想,如果傳入的參數(shù)值特別大,那么這個調(diào)用棧將會非常之大,最終可能超出調(diào)用棧的緩存大小而崩潰導(dǎo)致程序執(zhí)行失敗。注意尾遞歸不一定會將你的代碼執(zhí)行速度提高相反,可能會變慢。 譯者按: 程序員應(yīng)該知道遞歸,但是你真的知道是怎么回事么? 原文: All About Recursion, PTC, TCO and STC in JavaScript 譯者: Fundebug ...

    Jacendfeng 評論0 收藏0
  • 系列3|走進(jìn)Node.js之多進(jìn)程模型

    摘要:例如,在方法中,如果需要主從進(jìn)程之間建立管道,則通過環(huán)境變量來告知從進(jìn)程應(yīng)該綁定的相關(guān)的文件描述符,這個特殊的環(huán)境變量后面會被再次涉及到。 文:正龍(滬江網(wǎng)校Web前端工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處 之前的文章走進(jìn)Node.js之HTTP實(shí)現(xiàn)分析中,大家已經(jīng)了解 Node.js 是如何處理 HTTP 請求的,在整個處理過程,它僅僅用到單進(jìn)程模型。那么如何讓 Web 應(yīng)用擴(kuò)展到...

    snowell 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<