20分钟理解Node.js模型概念

1,429 阅读3分钟

名字

Node.js是唯一正确的名字。它不是一门语言,也不是一种框架,它是:

  • Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
  • Node.js 使用了一个事件驱动非阻塞式 I/O 的模型,使其轻量又高效。

基于 Chrome V8 引擎

我们所用JS写的Node.js代码,它是通过V8引擎(C++代码)来运行的,而里边涉及到对操作系统的调用,这一部分就会由v8引擎帮我们转发到我们的操作系统层面,从操作系统层面得到返回结果之后,再通过v8引擎返回到 JS 里边去。

在 Node.js 里运行 JavaScript 跟在 Chrome 里运行 JavaScript 有什么不同?

  • Node.js 没有浏览器 API ,即 document ,window 等。

  • 加了许多 Node.js API 。

  • 对于开发者来说,Node.js :

    • 你在 Chrome 里写 JavaScript 是在控制浏览器。
    • 而 Node.js 让你用类似的方式,控制整个计算机

事件驱动

概念

事件循环器(Event Loop)是一个程序结构,用于等待和发送消息和事件。事件驱动编程的代码核心就是事件循环器,在Linux下推荐使用epoll实现。

Event loop 和 event queue 一起工作, event queue就只是一个单纯的放置JavaScript functions的队列。我们把在event queue里面的 functions 叫做 events,当libuv完成任务, runtime会把关联的callback放到event queue,event loop在event queue和JavaScript engine中间, event loop的工作就是从event queue拿event放到JavaScript engine去执行

image.png

event loop遵守以下规则放event:

  • JavaScript Engine执行js代码时, event loop会暂停 -> 单线程
  • 如果JavaScript Engine有空, event loop就会把在event queue的第一个event放到JavaScript Engine,JavaScript Engine开始执行
  • 当涉及到I/O操作的时候,Node.js会开一个独立的线程来进行异步I/O操作,操作结束以后将消息压入event queue

事件源

事件源可以是任意一个继承自 Node.js 内置模块 events的EventEmitter类的实例。

const { EventEmitter } = require('events')

class MyModule extends EventEmitter{
  constructor(){
    super
  }
}

继承后,实例上会有多个与事件相关的属性。其中, _events 属性指向一个空对象,用于缓存事件类型和事件处理程序。
同时,实例也拥有了EventEmitter原型上的方法,emit on 等。

非阻塞式 I/O

概念

  • I/O 即 Input/Output,一个系统的输入和输出
  • 阻塞 I/O 和非阻塞 I/O 的区别就在于系统接收输入再到输出期间,能不能接收其他输入

进程

进程的五种状态:

image.png

阻塞的本质就是利用CPU中断,将进程挂起,并让出时间片(相当于告诉计算机,下一轮执行我不参与了),而唤醒阻塞的本质是:将进程的状态置为Runnable(相当于告诉计算机,下一轮我可以执行了)

image.png

非阻塞I/O就是好,阻塞I/O就全是缺点?

阻塞I/O优点:代码好理解,且阻塞时不会占用系统资源
阻塞IO缺点:高并发场景需要较高的线程数,资源占用大,且线程切换有成本

非阻塞I/O优点:操作不阻塞线程,读不到就返回null或者其它失败标识。所以,后面就需要持续重试,是需要搭配一定的编程手段去完善整个做法的,最简单的做法就是启个线程,不停的去检查有没有读到,这个就是I/O多路复用

课外知识

Node.js 真的有高并发优势么?