Node.js

  • 不是web框架
    • Node.js并不是web后端框架,不能把它跟Flask或Spring对比
  • 不是编程语言
    • Node.js并不是后端的JS,不能把它与Python或PHP做对比
  • Node.js是一个平台
    • 它将多种技术组合起来,让JavaScript可以调用系统接口、开发后端应用
    • 用到了下面这些技术
    1. V8引擎
    2. libuv
    3. C/C++实现的 c-ares、http-parser、OpenSSL、zlib等库

      技术架构

      | Node.js API
      http模块、fs模块、stream模块等 | | | | | | | —- | —- | —- | —- | —- | —- | | Node.js bindings
      让JS和C/C++通信 | | | C/C++插件
      自定义其他能力 | | | | JS引擎
      V8 | 跨平台的异步I/O能力
      libuv | | DNS解析
      c-ares | 加密解密
      OpenSSL | 其他…
      http-parser、z-lib等 |

《深入理解Node.js:核心思想与源码分析》

bindings

  • 背景
    • C/C++实现了一个http-parser库,很高效
    • JS无法直接调用这个库,需要一个中间的桥梁
  • bindings
    • Node.js用C++对http_parser进行封装,使它符合某些要求,封装的文件叫做http_parser_bindings.cpp
    • 用Node.js提供的编译工具将其编译为.node文件*
    • JS代码可以直接require这个.node文件
    • 这样JS就能调用C++库,中间的桥梁就是binding
    • 由于Node.js提供了很多binding,所以加个s
    • 这就是bindings

      JS与C++交互

      JS调用C++代码
      C++调用JS回调
      Node.js还提供了很多其他的交互方式

libuv

背景

  • 每个系统上的异步I/O都不一样
    • FreeBSD系统上有kqueue
    • Linux系统上有IOCP
  • Ryan为了一个跨平台的异步I/O库,开始写libuv
  • libuv会根据系统自动选择合适的方案

    功能

  • 可以用于TCP/UDP/DNS/文件等的异步操作

V8

功能

  • 将JS源代码变成本地代码并执行
  • 维护调用栈,确保JS函数的执行顺序
  • 内存管理,为所有对象分配内存
  • 垃圾回收,重复利用无用内存
  • 实现JS的标准库

    注意

  • V8不提供DOM API

  • V8执行JS是单线程的
  • 可以开启两个线程分别执行JS
  • V8本身是包含多个线程的,如垃圾回收为单独线程
  • 自带event loop但Node.js 基于 libuv 自己做了一个

Event Loop

Event

  • 计时器到期了
  • 文件可以读取了,读取出错了
  • socket有内容了,关闭了

  • Loop

  • loop就是循环,比如while(true)循环

  • 由于事件是分优先级的,所以处理起来也是分先后的
  • 所以Node.js需要按顺序轮询每种事件
  • 这种轮询往往都是循环的,1->2->3->1->2->3

  • 举例

  • 三种不同的事件

    • setTimeout(f1,100)
    • fs.readFile(‘/1.txt’,f2)
    • server.on(‘close’,f3)
  • 如果同时触发,Node会怎么办
    • 肯定会有某种顺序(优先级)
    • 这种顺序应该是人为规定的

Event Loop

  • 操作系统可以触发事件,JS可以处理事件
  • Event Loop就是对事件处理顺序的管理

    顺序示意图

    Event Loop、计时器、nextTick

    1. ┌───────────────────────┐
    2. ┌─>│ timers
    3. └──────────┬────────────┘
    4. ┌──────────┴────────────┐
    5. I/O callbacks
    6. └──────────┬────────────┘
    7. ┌──────────┴────────────┐
    8. idle, prepare
    9. └──────────┬────────────┘ ┌───────────────┐
    10. ┌──────────┴────────────┐ incoming:
    11. poll │<─────┤ connections,
    12. └──────────┬────────────┘ data, etc.
    13. ┌──────────┴────────────┐ └───────────────┘
    14. check
    15. └──────────┬────────────┘
    16. ┌──────────┴────────────┐
    17. └──┤ close callbacks
    18. └───────────────────────┘

    重点阶段

  • timers检查计时器

  • poll轮询,检查系统事件
  • check检查setImmediate回调
  • 其他阶段用得少

    注意

  • 大部分时间,Node.js都停在poll轮询阶段

  • 大部分事件都在poll阶段被处理,如文件、网络请求

Node.js工作流程

image.png