You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// lib/internal/process/next_tick.js'use strict';exports.setup=setupNextTick;functionsetupNextTick(){varnextTickQueue=[];// ...varkIndex=0;varkLength=1;process.nextTick=nextTick;process._tickCallback=_tickCallback;function_tickCallback(){varcallback,args,tock;do{while(tickInfo[kIndex]<tickInfo[kLength]){tock=nextTickQueue[tickInfo[kIndex]++];callback=tock.callback;args=tock.args;_combinedTickCallback(args,callback);if(1e4<tickInfo[kIndex])tickDone();}tickDone();}while(tickInfo[kLength]!==0);}functionnextTick(callback){if(typeofcallback!=='function')thrownewTypeError('callback is not a function');if(process._exiting)return;varargs;if(arguments.length>1){args=newArray(arguments.length-1);for(vari=1;i<arguments.length;i++)args[i-1]=arguments[i];}nextTickQueue.push(newTickObject(callback,args));tickInfo[kLength]++;}}// ...
大家可能会好奇,在 Node.js 启动后,第一个执行的 JavaScript 文件会是哪个?它具体又会干些什么事?
一步步来看,翻开 Node.js 的源码,不难看出,入口文件在
src/node_main.cc
中,主要任务为将参数传入node::Start
函数:node::Start
函数定义于src/node.cc
中,它进行了必要的初始化工作后,会调用StartNodeInstance
:而在
StartNodeInstance
函数中,又调用了LoadEnvironment
函数,其中的ExecuteString(env, MainSource(env), script_name);
步骤,便执行了第一个 JavaScript 文件代码:其中的
internal_bootstrap_node_native
,即为lib/internal/bootstrap_node.js
中的代码。(注:很多以前的 Node.js 源码分析文章中,所写的第一个执行的 JavaScript 文件代码为src/node.js
,但这个文件在 Node.js v5.10 中已被移除,并被拆解为了lib/internal/bootstrap_node.js
等其他lib/internal
下的文件,PR 为: nodejs/node#5103 )正文
作为第一段被执行的 JavaScript 代码,它的历史使命免不了就是进行一些环境和全局变量的初始化工作。代码的整体结构很简单,所有的初始化逻辑都被封装在了
startup
函数中:而在
startup
函数中,逻辑可以分为四块:process
对象上的部分属性 / 行为timer
方法console
等对象让我们一个个来解析。
初始化全局
process
对象上的部分属性 / 行为添加
process
上uncaughtException
事件的默认行为在 Node.js 中,如果没有为
process
上的uncaughtException
事件注册监听器,那么该事件触发时,将会导致进程退出,这个行为便是在startup
函数里添加的:逻辑十分直白,使用到了
EventEmitter#emit
的返回值来判断该事件上是否有注册过的监听器,并最终调用 c++ 的exit()
函数退出进程:根据 Node.js 在启动时所带的某些参数,来调整
process
上warning
事件触发时的行为具体来说,这些参数是:
--no-warnings
,--no-deprecation
,--trace-deprecation
和--throw-deprecation
。这些参数的有无信息,会先被挂载在process
对象上:然后根据这些信息,控制行为:
具体行为的话,文档中已经有详细说明,逻辑总结来说,就是按需将警告打印到控制台,或者按需抛出特定的异常。其中
NativeModule
对象为 Node.js 在当前的函数体的局部作用域内,实现的一个最小可用的模块加载器,具有缓存等基本功能。为
process
添加上stdin
,stdout
和stderr
属性通常为
tty.ReadStream
类和tty.WriteStream
类的实例:为
process
添加上nextTick
方法具体的做法便是将注册的回调推进队列中,等待事件循环的下一次 Tick ,一个个取出执行:
为
process
添加上hrtime
,kill
,exit
方法这些功能的核心实现也重度依赖于 c++ 函数:
hrtime
方法依赖于libuv
提供的uv_hrtime()
函数kill
方法依赖于libuv
提供的uv_kill(pid, sig)
函数exit
方法依赖于 c++ 提供的exit(code)
函数初始化全局的一些
timer
方法和console
等对象这些初始化都干的十分简单,直接赋值:
值得注意的一点是,由于
console
是通过__defineGetter__
赋值给global
对象的,所以在严格模式下给它赋值将会抛出异常,而非严格模式下,赋值将被忽略。开始执行用户执行指定的 JavaScript 代码
这一部分的逻辑已经在之前的文章中有所阐述,这边就不再重复说明啦。
最后
还是再次总结下:
lib/internal/bootstrap_node.js
中的代码 为 Node.js 执行后第一段被执行的 JavaScript 代码,从src/node.cc
中的node::LoadEnvironment
被调用lib/internal/bootstrap_node.js
主要进行了一些初始化工作:process
对象上的部分属性 / 行为uncaughtException
事件时的默认行为warning
事件的行为stdin
,stdout
和stderr
属性nextTick
,hrtime
,exit
方法timer
方法console
等对象参考:
The text was updated successfully, but these errors were encountered: