🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
核心模块被编译进二进制文件需要遵循一定的规则。作为Node的使用者,尽管几乎没有机会参与核心模块的开发,但是了解如何开发核心模块有助于我们更加深入的了解Node。 核心模块中的JavaScript部分几乎与文件模块的开发一样,遵循CommonJS模块规范,上下文中除了拥有require、module、exports外,还可以调用Node中的一些全局变量,这里不做描述。 下面我们以C/C++模块为例演示如何编写内建模块。为了便于理解,我们先编写一个极其简单的JavaScript版本的原型,这个方法返回一个Hello World! 字符串: ~~~ exports.sayHello = ()=>{ console.log('Hello World!'); }; ~~~ 编写内建模块通常分两步完成:编写头文件和编写C/C++文件。 (1).将以下代码保存为node_hello.h,存放到Node的src目录下: ~~~ #ifndef NODE_HELLO_H_ #define NODE_HELLO_H_ #include <v8.h> namespace node{ //预定义方法 v8::Handle<v8::Value> SayHello(const v8::Arguments& args); } #endif ~~~ (2).编写node_hello.cc,并存储到src目录下: ~~~ #include <node.h> #include <node_hello.h> #include <v8.h> namespace node{ using namespace v8; //实现预定义的方法 Handle<Value> SayHello(const Arguments& args){ HandleScope scope; return scope.Close(String::New("Hello World!")); } //给传入的目标对象添加sayHello方法 void Init_Hello(Handle<Object> target){ target=>Set(String::NewSymbol("sayHello"),FunctionTemplate::New(sayHello)->GetFunction()); } } //调用NODE_MODULE()将注册方法定义到内存中 NODE_MODULE(node_hello, node::Init_Hello) ~~~ 以上两步完成了内建模块的编写,但是真正要让Node认为它是内建模块,还需要更改`src/node_extensions.h`,在`NODE_EXT_LIST_END`前添加`NODE_EXT_LIST_ITEM(node_hello)`,以将`node_hello`模块添加到`node_module_list`数组中。 其次,还需要让编写的两份代码编译进执行文件,同时需要更改Node的项目生成文件node.gyp,并在'target_name':'node'节点的sources中添加上新编写的两个文件。然后编译整个Node项目,具体的编译步骤请参见附录A。 编译和安装后,直接在命令行中运行以下代码,将会得到期望的效果: ~~~ $ node > var hello =process.binding('hello'); undefined >hello.sayHello(); 'Hello World!' > ~~~ 至此,原生编写过程中需要注意的细节都已表述过了。可以看出,简单的模块通过JavaScript来编写可以大大提高生产效率。这里我们写作本书的目的是希望有能力的读者可以深入Node的核心模块,去学习它或者改进它。