Node.js [doing抄文档阶段,后续重写]
Node.js 就是运行在服务端的 JavaScript。(事件驱动、非阻塞I/O、高效、轻量)
问题提出
- Node的单线程如何理解
- Node是否能创建线程
- Node与底层如何进行I/O交互
- 为什么说Node是高性能的
- Node 的事件循环机制
- 使用Node 解析http请求的body数据
问题回答
完全参考:Node单线程
Node 结构
- Node.js 标准库,这部分是由 Javascript 编写的,即我们使用过程中直接能调用的 API。在源码中的 lib 目录下可以看到。
- Node bindings,这一层是 Javascript 与底层 C/C++ 能够沟通的关键,前者通过 bindings 调用后者,相互交换数据。实现在 node.cc。
- 这一层是支撑 Node.js 运行的关键,由 C/C++ 实现。 V8:Google 推出的 Javascript VM,也是 Node.js 为什么使用的是 Javascript 的关键,它为 Javascript 提供了在非浏览器端运行的环境,它的高效是 Node.js 之所以高效的原因之一。 Libuv:它为 Node.js 提供了跨平台,线程池,事件池,异步 I/O 等能力,是 Node.js 如此强大的关键。 C-ares:提供了异步处理 DNS 相关的能力。 http_parser、OpenSSL、zlib 等:提供包括 http 解析、SSL、数据压缩等其他的能力。
Libuv
本身事件驱动/异步
与操作系统交互
var fs = require('fs');
fs.open('./test.txt', "w", function(err, fd) {
//..do something
});
异步/非阻塞IO
【发起 I/O 调用】
-
用户通过 Javascript 代码调用 Node 核心模块,将参数和回调函数传入到核心模块;
-
Node 核心模块会将传入的参数和回调函数封装成一个请求对象;
-
将这个请求对象推入到 I/O 线程池等待执行; J* avascript 发起的异步调用结束,Javascript 线程继续执行后续操作。 【执行回调】
-
I/O 操作完成后,会将结果储存到请求对象的 result 属性上,并发出操作完成的通知;
-
每次事件循环时会检查是否有完成的 I/O 操作,如果有就将请求对象加入到 I/O 观察者队列中,之后当做事件处理;
-
处理 I/O 观察者事件时,会取出之前封装在请求对象中的回调函数,执行这个回调函数,并将 result 当参数,以完成 Javascript 回调的目的。
事件驱动
线程总结
- Node.js 通过 libuv 来处理与操作系统的交互,并且因此具备了异步、非阻塞、事件驱动的能力。
- Node.js 实际上是 Javascript 执行线程的单线程,真正的的 I/O 操作,底层 API 调用都是通过多线程执行的。
- CPU 密集型的任务是 Node.js 的软肋。