Node.js的由V8 engine,内建的模块以及libuv组成。 结合Node.js源代码以及图1,可以看出几点
- Node对外提供了标准的JS库,这些库包括了从HTTP,DNS等网络服务到File System, Child Processes等基础服务的一系列库
- 这些库是依赖于由C/C++写成的其它内建模块对外提供服务的
- 由libuv完成了最终的异步调用的工作
图1: Node.js overview
图2是我之前发表的一篇文章( 一个小例子浅析Node.JS架构)中所画的图。该图从V8 engine角度出发,描述了建立HTTP server时,从JS到C++的完整穿越过程。图2的过程既包括了V8所执行的JS和它所处的context,也包括了异步调用后端的参与者(Node.js TCPWrap以及libuv)。
本文将这个过程进一步细化,帮助需要的人从更细的角度看完整个过程。 图2:从V8到libuv异步调用过程
用Node.js建立一个HTTP server可谓方便至极也简单至极。寥寥十几行代码就完成了一个server的雏形。然而代码看似简单,背后必然发生了很多故事。暴露给应用开发者的接口越少,说明平台或者框架代替开发者做了越多的事情。
图3:创建http server的JS code
套用著名技术作家侯捷的一句话“只会用一样东西,不明白他的道理,实在不高明”。作为一个探索欲望挺强的人,我按捺不住好奇心深入框架研究了一番,努力做一个高明的人。
我的研究从代码http.createServer()开始。 图4展示了从V8开始执行图3的JS代码到TCPWrap的序列图。 图4:http server创建序列图
序列图从上至下分为2部分。第一部分创建了一个Server()的实例。这部分还是集中在JS部分。其中http.js, _http_server.js以及net.js是Node.js JS库中的一部分。这部分比较重要的细节是 _http_server.js中的Server()的prototype部分从net.js Server()集成了若干API(),这部分API会为之后提供服务。
第二部分开始从调用this.listen()开始。可以看到,第二部分直接调用net.js提供的API。让我们把注意力直接放到序列图的net.js 最后一步。
createTCP()通过process.binding(‘tcp_wrap’).TCP进入到Node.js C++部分。也就是图2所示的TCPWrap部分。new TCPWrap()是最先被调用的代码。从JS 到 C++如何穿越的问题,请参考V8 engine相关文档。
我们再来看看图4 net.js的倒数第二步 handle.open(fd)。这部分代码最终调用到C++部分的TCPWrap::Open()。
文章分析至此结束,后续部分大家可以按代码索骥,找到背后的故事。