Node.js开发——认识篇 | 青训营笔记

107 阅读6分钟

Node.js

前言

这是我参与「第四届青训营」笔记创作活动的的第3天

让我们一起了解认识Node.js到底有何魅力,学习它的一些使用方式吧!

什么是Node.js

  • Node.js 是一个开源和跨平台的 JavaScript 运行时环境。 它几乎是任何类型项目的流行工具!
  • Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 这使得 Node.js 的性能非常好。Node.js 应用程序在单个进程中运行,无需为每个请求创建新的线程。
  • Node.js 在其标准库中提供了一组异步的 I/O 原语,以防止 JavaScript 代码阻塞,通常,Node.js 中的库是使用非阻塞范式编写的,使得阻塞行为成为异常而不是常态。当 Node.js 执行 I/O 操作时(比如从网络读取、访问数据库或文件系统),Node.js 将在响应返回时恢复操作(而不是阻塞线程和浪费 CPU 周期等待)。这允许 Node.js 使用单个服务器处理数千个并发连接,而不会引入管理线程并发(这可能是错误的重要来源)的负担。
  • Node.js 具有独特的优势,因为数百万为浏览器编写 JavaScript 的前端开发者现在无需学习完全不同的语言,就可以编写除客户端代码之外的服务器端代码!

Node.js的应用场景

1. 前端工程化

随着前端工程化开发的不断发展,我们有了一些工具,这些工具就可以完成项目打包任务。这些工具都是要利用Node.js实现服务端的能力,或者说是可以在浏览器之外跑JavaScript的代码,调用操作系统的一些API来完成一些任务。反过来也能说是有了Node.js的出现,才促成了这些前端工程化工具出现。不管整么说node.js是前端工程化必不可缺的 image.png

  • Bundle:webpack,vite,esbuild,parcel
  • Uglify:uglifyjs
  • Transpile:bablejs,typescript
  • 其他语言加入竞争:基于go实现的ebuild,parcel,prisma

node.js 现状:虽然有这些其他语言的加入,但node.js在前端工程化中还是处于难以替代的地位,因为本身这些前端工程化的工具都是为了前端开发者服务的,既然这里的工具用户是前端开发者,那么大部分工具的开发者是偏向于前端开发,对于前端开发者而言,node.js相比于其他后端语言学习成本是更低的。所以在前端工程化里面,node.js还是处于难以替代的地位。哪怕你是属于纯前端开发,你也会经常使用node.js去开发这些工具。

2. web 服务端应用

在web服务端开发中,传统的后端语言有恒多,而node.js最大的特点优势:

  • 学习效率平缓,开发效率高
  • 运行效率接近常见的编程语言
  • 社区生态丰富及工具链成熟(npm,V8 inspector)
  • 与前端结合的场景会有优势(SSR)
较为突出的一个事就是 服务端渲染 ,我们希望把前端代码用在模板引擎代码的渲染上面,
让它去生成HTML,而不需要自己重复去写HTML代码,这样的话就是要执行JavaScript代码,
这种场景就是说基本上只有node.js可以做
复制代码

node.js 现状:在服务端语言中竞争极为激烈,或许node.js比不过其他传统的后端语言,但是它还是有其独特的优势。如对于一位前端开发者来说用node.js开发服务端应用,还是有极大帮助的,因为相比于其他服务端语言学习成本相对较低

3. Electron 跨端桌面应用

  • 商业应用:vscode, slack, discord, zoom等等的桌面应用都是用Electron开发的
  • 大型公司的效率工具,大部分都是基于 Electron 做的

现状:大部分场景在选型时,都值得考虑

4.node.js做的应用

  • BFF应用,SSR应用,如: Modern.js
  • 服务端应用:头条搜索,西瓜视频,懂车帝
  • Electron应用:飞书,飞连
  • 每年新增1000+ Node.js 应用

Node.js运行时结构

结构

image.png

  • V8:JavaScript Runtime,诊断调试工具(inspector)
  • libuv:eventLoop(事件循环),syscall(系统调用)
libuv实现事件循环,封装操作系统上的各种API实现跨平台的I/O操作
复制代码
  • eg:用 node-fetch 发起请求时...

解释:结合上图阐述 node-fetch 是如何运行的

用 node-fetch 发起请求时,首先通过npm安装node-fetch模块,之后在用户代码里面调用node-fetch模块,这些代码会在V8中执行,那么node-fetch执行是调用底层http模块(Node.js Core(JavaScript)),再去调用更底层的Node.js Core(c++),之后可能调用llhttp去做http的序列化与反序列化,然后把得到的数据再通过libuv,可能调用TCP连接,再把这个数据发给远端,远端返回数据,在事件循环中得到这个数据,在把拿到的数据给llhttp解析出来,得到的数据返回给Node.js Core(JavaScript),最后送到用户代码从而得到最终的数据。

Node.js运行时结构特点

1. 异步I/O

场景分析

image.png

当调用异步API(fs.readFile())读取文件时,会把读取文件的操作交给libuv的线程池去做,此时就不用等到文件读取完,就可以做其他调用,之后文件读取的操作从node线程处理完返回给主线程执行回调,然后在做其他事情。那么异步I/o的好处是什么呢?、

异步I/O好处: 当Node.js执行I/O操作时,会在响应返回后恢复操作,而不是阻塞线程并占用额外的内存等待

2. 单线程

  • js单线程

    • 实际:JS线程+ uv线程 +V8任务线程池 + V8 Inspector线程
  • 优点:不用考虑多线程状态同步问题,也就不需要锁🔒;同时还能比较有效的利用系统资源

  • 缺点:阻塞会产生更多的负面影响

    • 解决问题:多线程或多进程

3. 跨平台

  • 跨平台(大部分功能,api)

  • Node.js跨平台+JS无需编译环境(+web跨平台+诊断工具跨平台)

    • 开发成本低(大部分场景无需担心跨平台问题),整体学习成本低

Node.js 写服务端

安装node.js

编写http Server

简单写个服务器:

// 文件http_server.js
const http = require('http')

const port = 4000
const server = http.createServer((req, res) => {
  res.end('yes')
})

server.listen(port, () => {
  console.log(`server Listens on: ${port}`)
})
// 启动服务  node http_server.js
复制代码

最后在浏览器中输入网址localhost:4000就可以看到 hello

总结

让我们一起学习node.js,对于前端人员理解服务端的流程逻辑还是有极大裨益的!😀😁😊