Nodejs源码系列
一直想着看Nodej源码,断断续续的折腾了一下,但总串不起来,太久不看又忘记。决心每天看一点,特地记录在这里,作为逼迫自己的动力。
2019/09/22 一、源码编译
之前在电脑上了下源码,源码目录截图:

编译通过了,编译命令:make -j4
尝试修改下源码文件:lib/http.js,加入一行打印代码:
之后,编译 make -j4,第一次编译会花点时间,之后编译会快很多。编译之后,在当前目录下生成out/Release目录。
看看修改的代码是不是有效:
cd out/Release
./node
require('http')
可以看到打印出了required http haha,修改成功。
2019/09/23 二、node进程启动
入口文件:src/node_main.cc,

// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, );
setvbuf(stderr, nullptr, _IONBF, );
再调用了node::Start函数,传入参数。
int main(int argc, char* argv[]) {
...
return node::Start(argc, argv);
}
比如说使用 node /xxxx/test.js 执行时,argc是2,argv则是['/xxxx/node', '/xxxx/test.js'],第一个是node的执行路径。
再来看node::Start函数在src/node.cc文件:
int Start(int argc, char** argv) {
std::vector<std::string> args(argv, argv + argc); // 创建argv的拷贝
std::vector<std::string> exec_args;
// This needs to run *before* V8::Initialize().
Init(&args, &exec_args);
...
v8_platform.Initialize(
per_process_opts->v8_thread_pool_size);
V8::Initialize();
performance::performance_v8_start = PERFORMANCE_NOW();
v8_initialized = true;
const int exit_code =
Start(uv_default_loop(), args, exec_args);
v8_platform.StopTracingAgent();
v8_initialized = false;
V8::Dispose();
v8_platform.Dispose();
return exit_code;
}
可以大概看出流程:
一、Init函数初始化了些什么东西。
Init函数挺有意思,
void Init(std::vector<std::string>* argv,
std::vector<std::string>* exec_argv) {
// Initialize prog_start_time to get relative uptime.
prog_start_time = static_cast<double>(uv_now(uv_default_loop())); // Register built-in modules
RegisterBuiltinModules();
其中的RegisterBuiltinModules定义如下:
void RegisterBuiltinModules() {
#define V(modname) _register_##modname();
NODE_BUILTIN_MODULES(V)
#undef V
}
只是调用了NODE_BUILTIN_MODULES,传入了一个宏定义。而 NODE_BUILTING_MODULES定义在node_internals.h头文件:
#define NODE_BUILTIN_MODULES(V) \
NODE_BUILTIN_STANDARD_MODULES(V) \
NODE_BUILTIN_OPENSSL_MODULES(V) \
NODE_BUILTIN_ICU_MODULES(V)
NODE_BUILTIN_STANDARD_MODULES:
#define NODE_BUILTIN_STANDARD_MODULES(V) \
V(async_wrap) \
V(buffer) \
V(cares_wrap) \
V(config) \
V(contextify) \
V(domain) \
V(fs) \
V(fs_event_wrap) \
V(heap_utils) \
V(http2) \
V(http_parser) \
V(inspector) \
V(js_stream) \
V(messaging) \
V(module_wrap) \
V(options) \
V(os) \
V(performance) \
V(pipe_wrap) \
V(process_wrap) \
V(serdes) \
V(signal_wrap) \
V(spawn_sync) \
V(stream_pipe) \
V(stream_wrap) \
V(string_decoder) \
V(symbols) \
V(tcp_wrap) \
V(timer_wrap) \
V(trace_events) \
V(tty_wrap) \
V(types) \
V(udp_wrap) \
V(url) \
V(util) \
V(uv) \
V(v8) \
V(worker) \
V(zlib)
宏之间的互相调用,但是在node_internals.h里找不到async_wrap的定义,不知道在哪里定义的。(2019/09/28 增加)
二、初始化v8引擎。
三、调用Start函数,传入事件循环。具体看Start函数。
Start函数还是在node.cc文件:
inline int Start(uv_loop_t* event_loop,
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args) {
...
Isolate* const isolate = NewIsolate(allocator.get());
{
Mutex::ScopedLock scoped_lock(node_isolate_mutex);
CHECK_NULL(node_isolate);
node_isolate = isolate;
} int exit_code;
{
...
// 又调用了重载函数
exit_code = Start(isolate, isolate_data.get(), args, exec_args);
}
...
isolate->Dispose();
return exit_code;
}
找到重载函数Start:
inline int Start(Isolate* isolate, IsolateData* isolate_data,
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args) {
HandleScope handle_scope(isolate);
Local<Context> context = NewContext(isolate);
Context::Scope context_scope(context);
Environment env(isolate_data, context, v8_platform.GetTracingAgentWriter());
env.Start(args, exec_args, v8_is_profiling); const char* path = args.size() > ? args[].c_str() : nullptr;
...
{
Environment::AsyncCallbackScope callback_scope(&env);
env.async_hooks()->push_async_ids(, );
LoadEnvironment(&env);
env.async_hooks()->pop_async_id();
}
}
继续LoadEnvironment函数。
LoadEnvironment函数:
void LoadEnvironment(Environment* env) {
HandleScope handle_scope(env->isolate());
...
// 读internal/bootstrap/loaders.js文件内容
Local<String> loaders_name =
FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/loaders.js");
// 包裹刚才读取的loaders.js内容
MaybeLocal<Function> loaders_bootstrapper =
GetBootstrapper(env, LoadersBootstrapperSource(env), loaders_name);
// 读取node.js文件内容
Local<String> node_name =
FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/node.js");
// 包裹node.js,
MaybeLocal<Function> node_bootstrapper =
GetBootstrapper(env, NodeBootstrapperSource(env), node_name);
Local<Value> loaders_bootstrapper_args[] = {
env->process_object(),
get_binding_fn,
get_linked_binding_fn,
get_internal_binding_fn,
Boolean::New(env->isolate(),
env->options()->debug_options->break_node_first_line)
};
// Bootstrap internal loaders
Local<Value> bootstrapped_loaders;
// 执行loaders.js,得到一个对象:{ internalBinding, NativeModule }
if (!ExecuteBootstrapper(env, loaders_bootstrapper.ToLocalChecked(),
arraysize(loaders_bootstrapper_args),
loaders_bootstrapper_args,
&bootstrapped_loaders)) {
return;
} // Bootstrap Node.js
Local<Object> bootstrapper = Object::New(env->isolate());
SetupBootstrapObject(env, bootstrapper);
Local<Value> bootstrapped_node;
Local<Value> node_bootstrapper_args[] = {
env->process_object(),
bootstrapper,
bootstrapped_loaders
};
// node.js是一系列的函数调用,设置node进程全局变量,如设置process对象属性值
if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(),
arraysize(node_bootstrapper_args),
node_bootstrapper_args,
&bootstrapped_node)) {
return;
}
}
之后,就是进入事件循环。
Nodejs源码系列的更多相关文章
- 事件机制-Spring 源码系列(4)
事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...
- Ioc容器依赖注入-Spring 源码系列(2)
Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...
- Ioc容器BeanPostProcessor-Spring 源码系列(3)
Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...
- AOP执行增强-Spring 源码系列(5)
AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...
- 大白话Vue源码系列(02):编译器初探
阅读目录 编译器代码藏在哪 Vue.prototype.$mount 构建 AST 的一般过程 Vue 构建的 AST 题接上文,上回书说到,Vue 的编译器模块相对独立且简单,那咱们就从这块入手,先 ...
- 大白话Vue源码系列(03):生成AST
阅读目录 AST 节点定义 标签的正则匹配 解析用到的工具方法 解析开始标签 解析结束标签 解析文本 解析整块 HTML 模板 未提及的细节 本篇探讨 Vue 根据 html 模板片段构建出 AST ...
- 大白话Vue源码系列(03):生成render函数
阅读目录 优化 AST 生成 render 函数 小结 本来以为 Vue 的编译器模块比较好欺负,结果发现并没有那么简单.每一种语法指令都要考虑到,处理起来相当复杂.上篇已经生成了 AST,本篇依然对 ...
- 大白话Vue源码系列(04):生成render函数
阅读目录 优化 AST 生成 render 函数 小结 本来以为 Vue 的编译器模块比较好欺负,结果发现并没有那么简单.每一种语法指令都要考虑到,处理起来相当复杂.上篇已经生成了 AST,本篇依然对 ...
- 大白话Vue源码系列(05):运行时鸟瞰图
阅读目录 Vue 实例的生命周期 实例创建 响应的数据绑定 挂载到 DOM 节点 结论 研究 runtime 一边 Vue 一边源码 初看 Vue 是 Vue 源码是源码 再看 Vue 不是 Vue ...
随机推荐
- 通过mysql 连接远程数据库时,输入密码后,提示10060错误
能提示输入密码,说明网络能够连接,而且能连到服务器.输入密码后提示错误,说明应该是权限问题 解决方法: 一.进入mysql数据库命令行 二.输入use mysql; 三.设置root账号密码为1 ...
- 微信小程序双向绑定
欢迎加入前端交流群交流知识获取视频资料:749539640 vue.angular的双向绑定如下示例: <div> <input type="text" [(ng ...
- redis—持久化操作
简介 Redis是一种高级key-value数据库.它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富.有字符串,链表,集 合和有序集合.支持在服务器端计算集合的并,交和补集(d ...
- Python 内置函数进制转换的用法(十进制转二进制、八进制、十六进制)
↓ 2进制 8进制 10进制 16进制 2进制 - bin(int(x, 8)) bin(int(x, 10)) bin(int(x, 16)) 8进制 oct(int(x, 2)) - oct(in ...
- HashMap源码分析二
jdk1.2中HashMap的源码和jdk1.3中HashMap的源码基本上没变.在上篇中,我纠结的那个11和101的问题,在这边中找到答案了. jdk1.2 public HashMap() ...
- jQuery基础 (一)—样式篇
jQuery的优势 jQuery有很多特性和工具方法
- [转载]springboot--常用注解--@configration、@Bean
springboot--常用注解--@configration.@Bean @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME ...
- zuul网管配置其他服务时 HTTP Status 500 – Internal Server Error
1.这个错误是由三个原因导致的 (1).我在给类的接口命名的时候前面少加了一个/ (2)给zuul配置路由的时候多加了个服务名,serviceId名称就是spring的name,而不是eureka注入 ...
- 题解 BZOJ1026 & luogu P2657 [SCOI2009]windy数 数位DP
BZOJ & luogu 看到某大佬AC,本蒟蒻也决定学习一下玄学的数位$dp$ (以上是今年3月写的话(叫我鸽神$qwq$)) 思路:数位$DP$ 提交:2次 题解:(见代码) #inclu ...
- python3 threading.Lock() 多线程锁的使用
import threadingimport time lock = threading.Lock() #创建锁 def fun(data): try: lock.acquire(True) #锁定 ...