// Add a reference to the global object
Local<Object> global = env->context()->Global();
......
// Expose the global object as a property on itself
// (Allows you to set stuff on `global` from anywhere in JavaScript.)
global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global);
global和process是node中大家经常用到的两个对象,那么这两个对象又是如何被创建的,我们在我们的代码中为什么能够使用呢?本篇文章将为大家揭晓答案。
global
global对象在src/node.cc中的被创建,在bootstrap/node.js中被初始化。
创建
在src/node.cc的LoadEnvironment方法中,有以下几行代码是用来创建global对象的。
其中
env->context()->Global()
获取了当前context中的Global全局对象,global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global)
将全局对象本身挂载在其global对象上,这样全局对象中有了一个global对象指向了全局对象本身,我们在该context中可以直接使用global对全局对象的引用进行访问。以上程序之后,这样我们就可以在context的任何地方对全局对象进行操作。
初始化
初始化在
bootstrap/node.js
中进行,其在上述逻辑执行后被执行,所以可以直接操作全局对象。初始化代码分为以下几个部分:
1.为global挂载process、Symbol.toStringTag、buffer等属性
这里将process挂载在global上,这也是为什么我们可以在我们的用户代码直接访问process对象的原因。同时注意Symbol.toStringTag属性会在访问global.toString()时访问。
2.初始化timeout、console、URL
这里以setupGlobalTimeouts为例,主要是在global上挂载setImmediate等timeout相关的方法。
3.为global加上'assert', 'async_hooks', 'buffer'等属性
这里调用的是internal/modules/cjs/helpers下的addBuiltinLibsToObject方法,代码如下:
其中builtinLibs主要包含buffer、assert等常用的对象或方法。
process
process在src/env.cc的Environment::Start方法中被创建和初始化,同时在bootstrap/node.js也初始化了process对象。Environment::Start的调用函数是
src/node.cc
中的inline函数Start。创建
在Environment::Start中初始化process的逻辑如下:
这里面主要做了如下几件事:
这里需要注意的是set_process_object是从哪里来的呢?
在env-inl.h中有下面的宏定义:
从这里我们可以看出,set_process_object在这里定义,其真实调用的是processobject.Reset方法,那么v8::Local:: Reset方法又做了什么呢?
这里Reset方法在PersistentBase类下,这里顾名思义PersistentBase是Persistent handle的基类,调用Reset方法也就是重新给其赋值。
那么开始的Persistent handle process_object又是怎么来的呢?我们看env.h中的如下代码:
其中ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES这个宏我们上面见过,就是调用了多次V,只不过这里的V代表V8的handle声明,用在process_object上其实就是如下代码:
也就是声明了Persistent handle process_object,也就有了我们后面的利用PersistentBase::Reset进行赋值的操作了。
初始化
process的初始化出现在src/env.cc和bootstrap/node.js。
在src/env.cc中,其实调用的是node.cc中的SetupProcessObject方法,初始化代码比较长,下面摘出了比较具有代表性的代码:
这里首先获取从env中获取了process_object,然后设置了一个process.title的存取器,用来获取和设置title,这里的title获取调用了
uv_get_process_title
,实际上就是开辟了堆内存,copy了一份process_argv[0],也就是入口main函数的argv[0];接着使用READONLY_PROPERTY这个宏设置了process的只读属性version。READONLY_PROPERTY宏定义如下所示:在bootstrap/node.js中初始化process的代码如下:
这里主要初始化了process的set_push_values_to_array_function、execPath、错误处理以及国际化版本等。
总结
本文主要讲解了global、process的创建、初始化,以及为什么我们在我们的用户代码中可以对他们进行直接的访问。