初识Node.js | 青训营笔记

101 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

初识Node.js

一、重点内容

  1. Node.js 的应用场景
  2. Node.js 运行时结构

二、详细知识点

1、怎么安装Node.js?

  1. 从 Node.js 官网安装 nodejs.org/en/
  2. Mac, Linux 环境可以使用 nvm 进行安装 github.com/nvm-sh/nvm NVM_NODEJS_ORG_MIRROR=npmmirror.com/mirrors/nod… nvm install 16

2、前端工程化

  1. Bundle(打包工具):Webpack、vite、esbuild、parcel
  2. Uglify(代码压缩--转换,减少代码体积):uglifyjs
  3. Transpile(语法转换):bablejs、TypeScript
  4. 其他语言加入竞争:esbuild、parcel、prisma
  5. Node.js仍然处于难以替代的地位

3、Web服务端应用

  1. 学习曲线平缓,开发效率极高
  2. 运行效率接近常见的编译语言
  3. 社区生态丰富及工具链成熟(NPM, V8 inspector)
  4. 与前端结合的常见会有优势(SSR(服务端渲染))
  5. 现状:竞争激烈,但是Node.js有自己独特的优势
  • js熟悉的情况下,主要了解运行环境的不同。Node.js提供更多的API,开发效率高
  • Node.js不需要编译环境,运行效率高

4、Electron 跨端桌面应用

  1. 商业应用:VsCode,slack, discord,zoom
  2. 大型公司内部的效率工具
  3. 现状:大部分场景在选型时,都值得考虑使用Node.js

5、Node.js运行时结构

node.js最重要的是V8。很多由V8实现,效率高也大部分归功于V8 运行时结构.png 从上到下是从上层到底层

  • 社区npm代码: acron,node-inspect(诊断调试工具),npm
  • 用户代码:自己写的业务代码,还包括npm安装的包
  • Node.js Core(JavaScript): 内部由JavaScript代码写的模块
  • Node.js Core(C++):Node底层有更多是由C++代码去编写的
  • N-API:是在一些特定的场景,通过JavaScript代码没法满足的需求,举个例子当你有一些需要性能的需求,比如某个场景用JavaScript写的代码效率比较低,所以就需要一些N-API的一系列模块来实现这些能力
  • V8:JavaScript Runtime, JS运行时,JS执行引擎。V8提供inspector(诊断调试工具)
  • libuv:封装了各类操作系统的API,还提供了Node.js最核心的eventloop(事件循环) 和 syscall(系统调用)。它会去封装各类操作系统上的API,然后来提供一个跨平台I/O操作
  • nghttp2:提供了http2相关的模块
  • zlib:常见的压缩和解压缩的算法
  • c-ares:做的dns查询的库
  • llhttp: 做http协议的解析(序列化或反序列化)
  • OpenSSL:常用在网络层面上的加密和解密的工具

6、用node-fatch发起请求时,大概调用顺序:

  • 首先通过npm去安装node-fatch模块就到达用户代码
  • 然后在用户代码里面调用node-fatch模块,因为这些代码都是JavaScript代码,所以它会到底层V8里面去执行
  • 然后node-fatch底层调用Node.js Core(JavaScript) 里面的http模块
  • 然后http模块调用更底层的Node.js Core(C++) 的API
  • 然后可能去调用llhttp去做http协议的序列化和反序列化,把得到的数据通过libuv,可能会创建一个TCP/IP链接,再把这个数据发送给远端
  • 反之远端传送过来一些数据以后,事件循环里面就会得到这个消息,再把拿到的数据给llhttp解析出来,数据给到JavaScript代码再到用户代码,收到了整个数据

7、Node.js特点

(1) 异步IO

  • 当Node.js执行I/O操作时,会在响应返回后恢复操作,而不是阻塞线程并占用额外内存等待,系统资源利用率高。
  • 在调用异步API读取文件的时候,就会触发一个异步调用,然后就会将这个读取文件的操作交给libuv的线程池去做,主线程就不需要等待文件读取完成,就可以先去做其他调用,等线程池的读取文件操作结束返回数据给主线程就行了。

(2) 单线程

  • JS单线程:一般说Node.js是单线程是指JavaScript线程为单线程
  • 实际上Node还有其他线程:JS线程 + libuv线程池(4个线程) + V8任务线程池 + V8 Inspector线程;
  • libuv线程池: Node.js为了不阻塞一些操作,就会把一些操作(例如:异步读取文件)交给libuv线程池里面的线程执行,还包括一些对cpu消耗时间比较大的底层操作(例如加密解密)也会交给libuv线程池去操作,避免对主线程产生大的阻塞。
  • V8任务线程池:可以通过V8配置调整,大部分不会单独去调整这个。
  • V8 Inspector线程: 当V8做调试的时候,会使用这个线程,当做调试的时候,比如在代码中写了个死循环,这类调试工具在单独的线程上,可以调试死循环的问题

优点:

  • 不用考虑多线程状态同步问题,也就不需要锁的机制,不用考虑死锁状况。
  • 同时还能比较高效的利用系统资源

缺点:

  • 如果出现阻塞问题会产生更多的负面影响,可能有更多事情因为阻塞而滞后。不适合时间敏感场景。
  • 解决办法:多进程或多线程

(3) 跨平台

  • Node.js跨平台 + JS无需编译环境( + Web 跨平台 + 诊断工具跨平台 ) = 开发成本低(大部分场景无需担心跨平台问题),整体学习成本低
  • 例如我想使用Linux系统上面的socket,在windows上使用同样的代码也是做类似的事情,在跨平台方面上,使用Node.js的时候,它已经完成了绝大部分的工作,就不用考虑太大跨平台的问题

三、总结

  1. Node.js是一个基于Chrome V8引擎的JavaScript运行环境,Node.js是一个JavaScript运行时(Runtime),让 JavaScript 运行在浏览器之外的平台。
  2. Node.js的目的是为了实现高性能Web服务器,他首先看重的是事件机制和异步IO模型的优越性。