blog icon indicating copy to clipboard operation
blog copied to clipboard

node源码粗读(4):process对象底层实现

Open xtx1130 opened this issue 6 years ago • 5 comments

这篇文章主要对process对象底层的实现进行解读,所读的源码为9.2版本的代码,博文之中相关代码链接为博文发布之日的node主干分支的代码。

process的诞生

process的实现代码应该还是很容易看懂的,我们直接切到node.cc中寻找定义process的方法,用不了很长时间,你会发现SetupProcessObject方法,通过函数名就能很直观的发现这是定义process的地方,我们直接走到逻辑中去一窥究竟。
这段代码里重复最多的有两个地方,一个是宏READONLY_PROPERTY,另一个则是函数env->SetMethod(Environment::SetMethod)。其中不难发现,宏定义中调用的是obj->DefineOwnProperty,是用来给process定义方法的,而函数SetMethod调用的是:

 v8::Local<v8::Function> function =
      NewFunctionTemplate(callback)->GetFunction();
  const v8::NewStringType type = v8::NewStringType::kInternalized;
  v8::Local<v8::String> name_string =
      v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
  that->Set(name_string, function);
  function->SetName(name_string);

相信如果做过读者addon的话,对这段代码应该是比较熟悉了,可以看到,SetMethod是用来给process定义方法用的。

process在c++中的初始化

process在c++中的初始化操作则是在env.cc,大家可以注意一下它的外层函数为 Environment::Start

void Environment::Start(int argc,
                        const char* const* argv,
                        int exec_argc,
                        const char* const* exec_argv,
                        bool start_profiler_idle_notifier) {
//....
SetupProcessObject(this, argc, argv, exec_argc, exec_argv);
//....
}

接下来我们来看一下node.cc中的start函数: issue12-1 在这里我标注出来了两个地方,一个是env.Start 是对 Environment::Start的调用;而另一个则是LoadEnvironment(&env);LoadEnvironment之前已经介绍过了,在这里跟大家重温一段代码:

Local<Value> arg = env->process_object();
auto ret = f->Call(env->context(), Null(env->isolate()), 1, &arg);

在这里我们可以看到process作为了参数传入到了f中(Call为 Function::Call,f是Funciton的实例,其中包含了node入口文件bootstrap_node.js以及一坨代码还有从内存中拿出来的编译好的内置js文件),到此为止,我们可以看到c++正式把process抛出给js了。而process在这之前进行c++中的初始化,便可以很好的保证了抛出给bootstrap_node.js的process可用。

在bootstrap_node.js中的process

bootstrap_node.js 其实就是一个匿名函数,当然咯,也是所有js文件的“鼻祖”。如果读者简单或者不小心点开了./lib/internal/bootstrap_node.js,映入眼帘的第一行代码就是……注释。好了,看主要内容:那么很快你就会发现:

(function(process) {
//....
});

这就是bootstrap_node.js。重点在于我这个匿名函数居然还有个参数--process,联想一下我刚才分析的f->Call,然后你就会发现,原来这里接住了c++中吐出来的process。这时候我开始有点慌了……说好的全局的process呢?别着急,如果读者了解bootstrap_node,就肯定会知道,它里面有一个方法setupGlobalVariables ,其中就包含了:

global.process = process;

至此,整个process的过程就分析完了,process中还有几个比较重要的api,比如binding、std系列,以及还有moduleLoadList的生成,如果有时间的话,会继续给大家详细解剖。

xtx1130 avatar Dec 21 '17 07:12 xtx1130

qq 20171204150947

ghost avatar Dec 21 '17 07:12 ghost

可以分析下Event Loop相关模块么🐱

gnipbao avatar Jan 05 '18 08:01 gnipbao

@gnipbao 感觉这没啥可分析的啊。。。node源码层面涉及到的很少:开局一个uv_default_loop。。。后面全靠libuv。不过可以分析下lib库里面的timers,进而延伸到libuv,等下下篇文章吧,哈哈,下篇要写什么我已经想好了。

xtx1130 avatar Jan 05 '18 09:01 xtx1130

简约不简单,给大佬跪下了

sunstdot avatar Jan 18 '18 07:01 sunstdot

@sunstdot image

xtx1130 avatar Jan 18 '18 07:01 xtx1130