Node基础复习

169 阅读3分钟

Node.js [doing抄文档阶段,后续重写]

Node.js 就是运行在服务端的 JavaScript。(事件驱动、非阻塞I/O、高效、轻量)

问题提出
  • Node的单线程如何理解
  • Node是否能创建线程
  • Node与底层如何进行I/O交互
  • 为什么说Node是高性能的
  • Node 的事件循环机制
  • 使用Node 解析http请求的body数据
问题回答

完全参考:Node单线程

Node 结构

  1. Node.js 标准库,这部分是由 Javascript 编写的,即我们使用过程中直接能调用的 API。在源码中的 lib 目录下可以看到。
  2. Node bindings,这一层是 Javascript 与底层 C/C++ 能够沟通的关键,前者通过 bindings 调用后者,相互交换数据。实现在 node.cc。
  3. 这一层是支撑 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
});

具体来说,当我们调用 fs.open 时,Node.js 通过 process.binding 调用 C/C++ 层面的 Open 函数,然后通过它调用 Libuv 中的具体方法 uv_fs_open,最后执行的结果通过回调的方式传回,完成流程。需要说明的是,这一步是在编译的时候已经决定好的,并不是在运行时中。 Node.js 虽然说是用的 Javascript,但只是在开发时使用 Javascript 的语法来编写程序。真正的执行过程还是由 V8 将 Javascript 解释,然后由 C/C++ 来执行真正的系统调用,所以并不需要过分担心 Javascript 执行效率的问题。可以看出,Node.js 并不是一门语言,而是一个 平台

异步/非阻塞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 的软肋。