image.png
Nodejs 架构图

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.各个模块间调用执行过程

  1. 当 node test.js 执行时,node_main.cc首先被调用,这一步初始化了V8 engine和libuv执行环境。
  2. uv_run(env->event_loop,UV_RUN_ONCE)用于启动libuv event loop,而我们的js代码则会被传递到creatEnvironment(),最后交由V8处理。

image.png

3. V8模块详解

  1. #include "include/v8.h"
  2. #include "include/libplatform/libplatform.h"
  3. using namespace v8;
  4. int main(int argc, char* argv[]) {
  5. // V8初试化.
  6. V8::InitializeICU();
  7. Platform* platform = platform::CreateDefaultPlatform();
  8. V8::InitializePlatform(platform);
  9. V8::Initialize();
  10. // 创建isolate.
  11. Isolate* isolate = Isolate::New();
  12. {
  13. Isolate::Scope isolate_scope(isolate);
  14. // 创建HandleScope.
  15. HandleScope handle_scope(isolate);
  16. // 创建context 环境.
  17. Local<Context> context = Context::New(isolate);
  18. // 引入环境.
  19. Context::Scope context_scope(context);
  20. // 创建字符串.
  21. Local<String> source = String::NewFromUtf8(isolate, "'Hello' + ', World!'");
  22. // 编译字符串.
  23. Local<Script> script = Script::Compile(source);
  24. // Run,并且获取返回值.
  25. Local<Value> result = script->Run();
  26. // 转换为utf8,并且打印出来.
  27. String::Utf8Value utf8(result);
  28. printf("%s\n", *utf8);
  29. }
  30. // 关掉v8.
  31. isolate->Dispose();
  32. V8::Dispose();
  33. V8::ShutdownPlatform();
  34. delete platform;
  35. return 0;
  36. }
  1. isolate 代表一个V8实例,各个isolate是独立的(隔绝的),isolate中的obj无法再另一个isolate中被使用。
  2. context 代表执行js代码的虚拟机,在这个虚拟机中,集成了一些功能,例如math,json,date(),RegExp()等。一个isolate可以同时存在多个context,这些context可以自由切换。如下图所示。
  3. 在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封装。正如下图所示。

image.png

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

  1. 建立thread pool(只建立一次)
  2. 在每个请求req__上绑定与其相关的event loop, work queue, work(), done()
  3. thread worker()用来处理work queue里面的每个请求,并执行work()
  4. 通过uv_async_send()通知event loop执行done()

参考文章:
Nodejs的运行原理