前端面试要点(九):Node

157 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

前言

在面试和复习过程中总结的一些前端知识点,记录下来,风格较简洁,尽量涵盖内容要点和简单例子。本文是前端面试系列第九篇:Node,持续更新...

一、Node 的模块机制

Node 用 CommonJS 模块规范,保证了变量的作用域限制在本地而不会暴露到全局。

在 Node 中引入模块,需要经历 3 个步骤:路径分析、文件定位、编译执行

在 Node 中,模块分为两类:一类是 Node 提供的模块,称为核心模块;另一类是用户编写的模块,称为文件模块

  1. 核心模块在 Node 源代码的编译过程中,编译进了二进制执行文件。在 Node 进程启动时,部分核心模块就被直接加载进内存中,所以这部分核心模块引入时,文件定位和编译执行这两个步骤可以省略掉,并且在路径分析中优先判断,所以它的加载速度是最快的。
  2. 文件模块则是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程,速度比核心模块慢。

Node 的模块加载机制是在第一次调用 requrie 之后缓存模块,之后这个模块的调用都是从缓存中读取。

二、Node 事件循环与浏览器的有哪些区别

浏览器和 Node 环境下,microtask 任务队列的执行时机不同:

  • 浏览器端,microtask 在事件循环的 macrotask 执行完之后执行;
  • Node 端,microtask 在事件循环的各个阶段之间执行,node 事件循环分为 6 个阶段;

process.nextTick,是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。

浏览器中,宏任务队列可以有多个,微任务队列只有一个。

三、cluster 原理

  • node 本身在一个 CPU 中进行运算,无法充分利用服务器的多核 CPU。Node 的 cluster 模块,不仅提供了开箱即用的能力去使用服务器的多核 CPU,而且还提供一个零停机时间重新启动整个应用程序的能力,提高 Node 进程的可用性。
  • cluster 模块基于 child_process 模块的 fork 方法,多次 fork 主进程,产生多个子进程,这样就可以使用多核 CPU,充分利用了服务器的资源。这种方式主进程监听一个端口,子进程不监听端口,通过主进程分发请求到子进程,支持负载均衡。

四、流机制

流分为缓冲模式对象模式,缓冲模式只能处理 buffer 或字符串,对象模式可以处理 js 对象。

流又分为四种类型:可读流可写流双工流转换流。后两种其实是对可读和可写流的应用。

可读流有两种模式,并随时可以转换,我们可以通过监听可读流的事件来操作它。

  1. 流动模式:可读流自动读取数据,通过 EventEmitter 接口的事件尽快将数据提供给应用。
  2. 暂停模式:必须显式调用 stream.read() 方法来从流中读取数据片段。

可写流相对较为简单,我们也可以通过监听它的事件来操作它。

五、守护进程

创建守护进程的过程

  1. 在当前进程中创建一个子进程;
  2. 调用 setsid 方法(setsid 作用是把该进程变成一个新会话的领导);
  3. 退出当前进程,子进程变成一个守护进程。

守护进程最重要的是稳定,如果守护进程挂掉,那么其管理的子进程都将变为孤儿进程,同时被 init 进程接管,这是我们不愿意看到的。于此同时,守护进程对于子进程的管理也是有非常多的发挥余地的,例如 pm2 中,将一个进程同时启动 4 次,达到 CPU 多核使用的目的(很有可能你的进程在同一核中运行),进程挂掉后自动重启等等,这些事情等着我们去造轮子。

六、进程通信

不同电脑上的两个 Node.js 进程间通信,通常使用 TCPHTTP 进行通信,利用三元组(协议,ip 地址,端口)可以标识网络的进程。

同一台电脑上两个 Node.js 进程间通信:

  • Node 进程和自己创建的 Node 子进程通信,可以使用内置的 IPC(Inter-Process Communication)通信通道,child_process 模块中的 fork 方法自带通信机制
  • Node 进程和另外不相关的 Node 进程通信,可以使用自定义管道

七、node 的异常处理方式

  • 同步代码中的异常使用 try{} catch 结构即可捕获处理。
  • 异步代码的错误处理使用 domain 模块,把处理多个不同的 IO 的操作作为一个组。注册事件和回调到 domain,当发生一个错误事件或抛出一个错误时,domain 对象会被通知,不会丢失上下文环境,也不导致程序错误立即退出。一种比较好的方案是,以多进程(cluster)的模式去部署应用,当某一个进程被异常捕获后,可以做一下打点上报后,开始重启释放内存,此时其他请求被接受后,其他进程依旧可以对外提供服务,当然前提是你的应用不能异常多的数都数不清。