核心模块被编译进二进制文件需要遵循一定的规则。作为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的核心模块,去学习它或者改进它。
- 目录
- 第1章 Node 简介
- 1.1 Node 的诞生历程
- 1.2 Node 的命名与起源
- 1.2.1 为什么是 JavaScript
- 1.2.2 为什么叫 Node
- 1.3 Node给JavaScript带来的意义
- 1.4 Node 的特点
- 1.4.1 异步 I/O
- 1.4.2 事件与回调函数
- 1.4.3 单线程
- 1.4.4 跨平台
- 1.5 Node 的应用场景
- 1.5.1 I/O 密集型
- 1.5.2 是否不擅长CPU密集型业务
- 1.5.3 与遗留系统和平共处
- 1.5.4 分布式应用
- 1.6 Node 的使用者
- 1.7 参考资源
- 第2章 模块机制
- 2.1 CommonJS 规范
- 2.1.1 CommonJS 的出发点
- 2.1.2 CommonJS 的模块规范
- 2.2 Node 的模块实现
- 2.2.1 优先从缓存加载
- 2.2.2 路径分析和文件定位
- 2.2.3 模块编译
- 2.3 核心模块
- 2.3.1 JavaScript核心模块的编译过程
- 2.3.2 C/C++核心模块的编译过程
- 2.3.3 核心模块的引入流程
- 2.3.4 编写核心模块
- 2.4 C/C++扩展模块
- 2.4.1 前提条件
- 2.4.2 C/C++扩展模块的编写
- 2.4.3 C/C++扩展模块的编译
- 2.4.2 C/C++扩展模块的加载
- 2.5 模块调用栈
- 2.6 包与NPM
- 2.6.1 包结构
- 2.6.2 包描述文件与NPM
- 2.6.3 NPM常用功能
- 2.6.4 局域NPM
- 2.6.5 NPM潜在问题
- 2.7 前后端共用模块
- 2.7.1 模块的侧重点
- 2.7.2 AMD规范
- 2.7.3 CMD规范
- 2.7.4 兼容多种模块规范
- 2.8 总结
- 2.9 参考资源
- 第3章 异步I/O
- 3.1 为什么要异步I/O
- 3.1.1 用户体验
- 3.1.2 资源分配
- 3.2 异步I/O实现现状
- 3.2.1 异步I/O与非阻塞I/O
- 3.2.2 理想的非阻塞异步I/O
- 3.2.3 现实的异步I/O
- 3.3 Node的异步I/O
- 3.3.1 事件循环
- 3.3.2 观察者
- 3.3.3 请求对象
- 3.3.4 执行回调
- 3.3.5 小结
- 3.4 非I/O的异步API
- 3.4.1 定时器
- 3.5 事件驱动与高性能服务器