这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天
初识Node.js
一、重点内容
- Node.js 的应用场景
- Node.js 运行时结构
二、详细知识点
1、怎么安装Node.js?
- 从 Node.js 官网安装 nodejs.org/en/
- Mac, Linux 环境可以使用 nvm 进行安装 github.com/nvm-sh/nvm NVM_NODEJS_ORG_MIRROR=npmmirror.com/mirrors/nod… nvm install 16
2、前端工程化
- Bundle(打包工具):Webpack、vite、esbuild、parcel
- Uglify(代码压缩--转换,减少代码体积):uglifyjs
- Transpile(语法转换):bablejs、TypeScript
- 其他语言加入竞争:esbuild、parcel、prisma
- Node.js仍然处于难以替代的地位
3、Web服务端应用
- 学习曲线平缓,开发效率极高
- 运行效率接近常见的编译语言
- 社区生态丰富及工具链成熟(NPM, V8 inspector)
- 与前端结合的常见会有优势(SSR(服务端渲染))
- 现状:竞争激烈,但是Node.js有自己独特的优势
- js熟悉的情况下,主要了解运行环境的不同。Node.js提供更多的API,开发效率高
- Node.js不需要编译环境,运行效率高
4、Electron 跨端桌面应用
- 商业应用:VsCode,slack, discord,zoom
- 大型公司内部的效率工具
- 现状:大部分场景在选型时,都值得考虑使用Node.js
5、Node.js运行时结构
node.js最重要的是V8。很多由V8实现,效率高也大部分归功于V8
从上到下是从上层到底层
- 社区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的时候,它已经完成了绝大部分的工作,就不用考虑太大跨平台的问题
三、总结
- Node.js是一个基于Chrome V8引擎的JavaScript运行环境,Node.js是一个JavaScript运行时(Runtime),让 JavaScript 运行在浏览器之外的平台。
- Node.js的目的是为了实现高性能Web服务器,他首先看重的是事件机制和异步IO模型的优越性。