1.Nodejs核心模块
- native modules:它是由js写成,提供我们应用程序调用的库,同时这些模块又依赖builtin modules来获取相应的服务支持,依赖V8作为宿主环境;
- builtin modules:它是由C++代码写成各类模块,包含了crypto,zlib, file stream etc 基础功能。(v8提供了函数接口,libuv提供异步IO模型库,以及一些nodejs函数,为builtin modules提供服务)。
- v8 engine:1.虚拟机的功能,执行js代码 2.提供C++函数接口,为nodejs提供v8初始化,创建context,scope等。
- libuv:libuv是一个多平台的,主要用于处理事件驱动的异步I/O模型库。并提供系统底层标准库
2.各个模块间调用执行过程
- 当 node test.js 执行时,node_main.cc首先被调用,这一步初始化了V8 engine和libuv执行环境。
- uv_run(env->event_loop,UV_RUN_ONCE)用于启动libuv event loop,而我们的js代码则会被传递到creatEnvironment(),最后交由V8处理。
3. V8模块详解
#include "include/v8.h"
#include "include/libplatform/libplatform.h"
using namespace v8;
int main(int argc, char* argv[]) {
// V8初试化.
V8::InitializeICU();
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// 创建isolate.
Isolate* isolate = Isolate::New();
{
Isolate::Scope isolate_scope(isolate);
// 创建HandleScope.
HandleScope handle_scope(isolate);
// 创建context 环境.
Local<Context> context = Context::New(isolate);
// 引入环境.
Context::Scope context_scope(context);
// 创建字符串.
Local<String> source = String::NewFromUtf8(isolate, "'Hello' + ', World!'");
// 编译字符串.
Local<Script> script = Script::Compile(source);
// Run,并且获取返回值.
Local<Value> result = script->Run();
// 转换为utf8,并且打印出来.
String::Utf8Value utf8(result);
printf("%s\n", *utf8);
}
// 关掉v8.
isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
}
- isolate 代表一个V8实例,各个isolate是独立的(隔绝的),isolate中的obj无法再另一个isolate中被使用。
- context 代表执行js代码的虚拟机,在这个虚拟机中,集成了一些功能,例如math,json,date(),RegExp()等。一个isolate可以同时存在多个context,这些context可以自由切换。如下图所示。
- 在V8 engine中,通过handle访问存在与heap上的js obj,如local,persistent,eternal,在V8中,有一个handle stack用于管理这些handles,如下图所示。
4. Libuv模块:
libuv通过epoll,kqueue,event ports和IOCP来实现异步network IO。file,dns的操作则依赖于thread pool 来实现,类似kernel封装。正如下图所示。
4.1Network I/O
V8 engine执行从server.listen() 开始,调用builtin module Tcp_wrap 的过程。
在创建TCP链接的过程中,libuv直接参与Tcp_wrap.cc函数中的 TCPWrap::listen() 调用uv_listen()开始到执行uv_io_start()结束。看起来很短暂的过程,其实是类似linux kernel的中断处理机制。
uv_io_start()负载将handle插入到处理的water queue中。这样的好处是请求能够立即得到处理。中断处理机制里面的下半部分与数据处理操作相似,交由主线程去完成处理。
4.2File I/O
- 建立thread pool(只建立一次)
- 在每个请求req__上绑定与其相关的event loop, work queue, work(), done()
- thread worker()用来处理work queue里面的每个请求,并执行work()
- 通过uv_async_send()通知event loop执行done()
参考文章:
Nodejs的运行原理