认识Node.js及其与 Nginx 前端项目区别
1、什么是node.js?
node.js是一个平台,或者说是一个运行环境。Node.js 是一个开源、跨平台的 JavaScript 运行时环境,它允许开发者在服务器端运行 JavaScript 代码。
1.1、node运行方式
通过cmd进入Node.js就要在cmd中输入node
1.2、node.js前端应该了解些什么?
1.2.1、安装和设置Node.js环境:
要开始使用Node.js,首先需要访问官方网站,下载并安装最新版本的Node.js。然后配置系统的环境变量,确保可以在命令行中运行Node.js和npm(Node包管理器)命令。
// 查看 node 版本
node -v
// 列出 Node 版本
nvm ls
// 切换 Node 版本
nvm use xxx
1.2.2、核心能力模块:
Node.js提供了一系列的核心模块,如:
fs
:文件系统操作。http
:创建 HTTP 服务器。path
:处理文件路径。os
:获取操作系统信息。events
:事件驱动机制。
1.2.3、重点能力-异步编程:
Node.js 的重点能力是 异步编程,这是因为它的核心设计基于 事件驱动 和 非阻塞 I/O 模型。这种设计使得 Node.js 在处理高并发和 I/O 密集型任务时非常高效。
1.单线程模型:
- Node.js 使用单线程处理所有任务,但通过事件循环(Event Loop)和异步 I/O 实现高并发。
- 单线程意味着 Node.js 不会为每个请求创建新的线程,而是通过异步回调处理多个请求。
- 注意:在 Node.js 中,单线程的意思是:
- Node.js 的主线程(也叫事件循环线程)只有一条执行路径,用于处理 JavaScript 代码的执行。
- 主线程不会为每个请求创建新的线程,而是通过 事件循环(Event Loop) 和 异步回调 来管理任务。
单线程并不意味着 Node.js 只能处理一个任务,而是通过异步机制将耗时的任务交给其他线程或系统模块处理,主线程继续执行其他任务。
2.非阻塞 I/O:
3.事件驱动:
- Node.js 的 I/O 操作(如文件读写、网络请求、数据库查询)是非阻塞的。
- 这意味着当一个 I/O 操作正在进行时,Node.js 不会等待其完成,而是继续处理其他任务。
- Node.js 使用事件循环来监听和处理异步任务。
- 当异步操作完成时,会触发相应的回调函数,将结果返回给主线程。
1.2.4、使用npm管理依赖:
npm是Node.js的包管理器,可用于安装、管理和发布JavaScript模块。需要学习如何使用npm安装第三方模块,并管理项目的依赖关系。
- 了解 npm(Node Package Manager)或 Yarn,用于管理项目依赖。
- 学习如何安装、更新和删除依赖包。
1.2.5、构建Web应用:
学习使用Node.js构建Web服务器和处理HTTP请求。
- 现代前端开发中,许多构建工具基于 Node.js,例如:
- Webpack:模块打包工具。
- Vite:快速构建工具。
- Rollup:用于打包库的工具。
- Parcel:零配置打包工具。
- 学习如何使用这些工具进行代码打包、压缩、转译(如 Babel)等操作。
1.2.6、调试和故障排查:
1.API 调试:
- 使用 Node.js 创建简单的 API 服务,模拟后端接口,方便前端开发和调试。
- 示例:使用 Express 创建一个 RESTful API。
2.代理服务:
3.Mock 数据:
- 使用 Node.js 搭建代理服务器,解决跨域问题。
- 示例:通过
http-proxy-middleware
转发请求。 - 使用工具如 json-server 或 Mock.js,通过 Node.js 快速生成模拟数据。
1.2.7、性能优化:
1、非阻塞 I/O:
2、流(Streams):
3、中间件:
- 理解 Node.js 的事件循环和异步编程模型。
- 学习如何使用
async/await
或回调处理异步操作。 - 学习如何使用 Node.js 的流处理大文件(如文件上传、下载)。
- 学习如何在框架(如 Express)中使用中间件处理请求。
......
1.2.8、总结
Node.js 对前端开发者来说,不仅是一个后端工具,更是现代前端开发的重要组成部分。通过学习 Node.js,前端开发者可以更高效地构建工具链、处理服务端逻辑、优化前后端协作,并提升全栈开发能力。
1.3、 Node.js 是如何实现异步回调的?
单线程的含义:
Node.js 的主线程只有一条执行路径,用于处理 JavaScript 代码。
单线程并不意味着只能处理一个任务,而是通过异步机制实现高并发。
单线程如何实现异步?
Node.js 使用事件循环、线程池和系统模块,将耗时任务交给其他线程或系统处理。
主线程继续执行其他任务,异步任务完成后通过回调函数返回结果。
异步编程的意义:
避免阻塞主线程,提高性能。
适合处理 I/O 密集型任务(如文件操作、网络请求、数据库查询)。
Node.js 的单线程模型结合异步编程,使其在高并发场景下表现出色,同时避免了多线程编程中的复杂性(如线程同步、死锁等问题)。
1.3.1、 事件循环(Event Loop)
事件循环(Event Loop):指的就是同步、异步的任务分别进入不同的执行环境,最后都同步回归主线程,即主执行栈,异步进入到任务 队列 (Event Queue)。 主线程串行执行任务完毕后,会去任务队列(Event Queue)读取相应的任务,继续串行在主线程执行。 以上不断重复的过程被成为事件循环。
Node.js 的核心是 事件循环,它负责管理异步任务的执行。事件循环的工作流程如下:
1、主线程执行同步代码:
- 主线程会先执行所有同步代码。
- 如果遇到异步任务(如 I/O 操作、定时器等),会将这些任务交给系统模块或线程池处理。
2、异步任务完成后,将回调函数放入任务队列:
- 异步任务完成后,会将对应的回调函数放入事件循环的任务队列中。
3、主线程从任务队列中取出回调函数执行:
- 主线程会不断检查任务队列,如果有回调函数,就取出并执行。
const fs = require('fs');console.log('Start');// 异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {if (err) throw err;console.log('File content:', data);
});console.log('End');// 执行流程
// 主线程执行同步代码,打印 Start。
// 遇到 fs.readFile,将文件读取任务交给线程池处理,并继续执行后续代码。
// 主线程打印 End。
// 文件读取完成后,线程池将回调函数放入任务队列。
// 主线程从任务队列中取出回调函数并执行,打印文件内容。// 输出结果
// Start
// End
// File content: <文件内容>
1.3.2 、异步任务的分类
rocess.nextTick
和 Promise
都是微任务(Microtasks),但它们的执行优先级不同。
process.nextTick
的回调会在当前操作结束后立即执行,优先级高于Promise
。Promise
的回调会在当前操作结束后,且所有process.nextTick
回调执行完毕后执行。
Node.js 中的异步任务主要分为两类:
- 宏任务(Macro Task):
- 包括
setTimeout
、setInterval
、setImmediate
、I/O 操作、DOM 事件、script
标签等。2.微任务(Micro Task):
- 包括Promise的then、catch、Mutation0bserver、queueMicrotask(特殊:process.nextTick是微任务最早的)等。
事件循环的优先级是:先执行微任务,再执行宏任务。
例子:
console.log('task1')setTimeout(()=>{new Promise((resolve,reject)=>{console.log('task2')resolve()}).then(()=>{console.log('task4')}).then(()=>{console.log('task7')})},0)new Promise((resolve,reject)=>{console.log('task3')resolve()}).then(()=>{console.log('task6')})console.log('task5')
1.同步任务
- 执行
console.log('task1')
,输出task1
- 遇到
setTimeout
,当time
时间结束时将其回调函数注册并放入宏任务队列 - 执行
new Promise
中的执行器函数,输出task3
- 执行器函数中的
resolve
方法执行,将then
的回调函数注册到微任务队列 - 执行
console.log('task5')
,输出task5
- 至此,第一轮的同步任务执行完毕
2.微任务队列
- 执行
then
的回调函数,输出task6
- 微任务队列清空
最终输出顺序是:task1 task3 task5 task6 task2 task4 task7
2、 基于 Node.js 服务器 和 基于 Nginx 转发 的前端项目区别
2.1、 核心概念
- 基于 Nginx 的前端项目:
1.角色: Nginx 是一个高性能的 静态资源服务器 和 反向代理/负载均衡器。
2.特点:
3.工作方式:
它接收用户浏览器的请求,然后直接从服务器的文件系统上找到对应的 HTML、CSS、JS、图片等静态文件,并将其快速地发送给浏览器。它只负责“分发”,不负责“执行”前端代码(浏览器会执行JS)。如果涉及API请求,它会将这些请求转发(Proxy Pass) 到后端的应用服务器(如 Java, Python, Go, Node.js 应用)。
- 高并发处理能力:Nginx使用事件驱动的方式处理请求,能够同时处理数万甚至数十万个并发连接。
- 轻量级:Nginx是一个轻量级的服务器,占用的系统资源非常少。
- 反向代理:Nginx可以充当反向代理服务器,将客户端请求转发到后端服务器。
1.角色: Node.js 是一个 JavaScript 运行时环境,可以运行服务器端程序。同时提供非阻塞I/O模型,这使得Node.js非常适合构建高性能、可扩展的网络应用程序。
- 基于 Node.js 的前端项目:
2.特点:
- 单线程异步I/O:Node.js使用事件循环和异步I/O模型,这使得它能够同时处理大量并发连接。
- 非阻塞I/O:通过非阻塞I/O,Node.js能够避免长时间等待I/O操作完成,从而提高应用程序的响应速度。
- 模块化:Node.js支持CommonJS模块系统,这使得代码组织和管理变得容易。
3.工作方式: 你使用 Node.js 编写了一个服务器程序(通常使用 Express、Koa 等框架)。这个程序会监听HTTP请求。当请求到来时,由这个 Node.js 程序来决定如何响应。它可以直接返回一个静态文件,也可以先执行一些服务器端的逻辑(比如服务器端渲染 SSR、用户认证、日志记录、连接数据库等),再生成 HTML 内容返回给浏览器。
2.2、 详细对比
特性维度 | 基于 Nginx 的前端项目 | 基于 Node.js 的前端项目 |
核心角色 | 静态文件服务者、反向代理 | 动态Web应用服务器 |
处理逻辑 | 简单、直接。收到URL,映射到磁盘文件,返回内容。 | 复杂、灵活。收到请求,可以执行任意JS代码逻辑,再生成响应。 |
性能 | 极高。处理静态资源是Nginx的强项,内存占用低,并发能力极强(基于事件驱动和异步IO)。 | 较高,但通常低于Nginx处理静态资源。Node.js也是异步IO,但应用逻辑本身会消耗CPU和内存。 |
功能 | 相对单一。主要功能:静态服务、反向代理、负载均衡、缓存、Gzip压缩、SSL终止等。 | 极其丰富。可以做任何事情: |
适用场景 | 纯静态网站、传统SPA(单页应用)、作为CDN源站、作为后端API的网关。 | 服务端渲染(SSR)应用(如Next.js, Nuxt.js)、同构应用、前端需要少量后端逻辑的项目(如轻量级API)、全栈JavaScript应用(如MERN/MEAN栈)。 |
配置方式 | 主要通过修改 配置文件,语法自成体系。 | 通过编写 JavaScript 代码,对前端开发者更友好,更灵活。 |
SEO(搜索引擎优化) | 对传统SPA不友好。因为SPA的HTML初始内容通常是空的,靠JS异步加载,搜索引擎爬虫可能无法获取完整内容。 | 友好。尤其是SSR应用,服务器直接返回渲染好的完整HTML,利于搜索引擎抓取。 |
开发流程 | 开发时通常使用 webpack-dev-server 等工具,生产环境才用Nginx。 |
2.3、现代最流行的架构:两者结合
在实际的生产环境中,几乎不会二选一,而是将它们结合起来,发挥各自最大的优势。Node.js 本身可以作为一个独立的服务器运行,但在实际生产环境中,通常会结合 Nginx 使用,以充分发挥两者的优势。
这是一种非常经典且高效的架构。对于绝大多数现代前端项目,尤其是React、Vue等框架构建的项目,在生产环境中使用 Nginx 作为静态服务器和反向代理,将动态请求转发给 Node.js(或其它后端语言)服务,是最佳实践。 纯Node.js提供服务更适合全栈项目或需要SSR等特定功能的场景,而纯Nginx则适用于最简单的静态展示页面。
典型工作流程:
1.用户请求
https://www.example.com
2.Nginx (最外层):最先接收到请求。它承担第一道防线和流量指挥官的角色。
- 静态文件请求(如
/static/js/main.js
,/images/logo.png
):Nginx 直接快速地从磁盘读取并返回,不再劳烦后面的Node.js,极大减轻应用服务器压力。- 动态请求(如 页面请求
/
,/about
, 或API请求/api/users
):Nginx 通过proxy_pass
将请求转发给后端的 Node.js 应用服务器。3.Node.js 服务器:接收到Nginx转发的请求。
- 如果是页面请求(如
/
),它可能执行SSR,从数据库获取数据,渲染出完整的HTML页面。- 如果是API请求(如
/api/users
),它执行业务逻辑,查询数据库,返回JSON数据。4.响应返回:Node.js 将处理结果返回给 Nginx,Nginx 再最终返回给用户的浏览器。
这种架构的优势:
- 性能最大化:Nginx高效处理静态资源,Node.js专心处理动态逻辑。
- 安全性增强:Nginx可以作为安全屏障,隐藏后端Node.js服务器的真实端口和内部结构,处理SSL、防止DDoS攻击等。
- 可靠性提升:Nginx可以轻松做负载均衡,后面挂载多个Node.js实例,实现高可用。
- 便于扩展:每层都可以独立地进行水平扩展。
2.4、总结
Node.js 并不强制要求使用 Nginx,但在生产环境中,结合 Nginx 可以显著提升性能和安全性。Nginx 负责处理静态资源和请求分发,而 Node.js 专注于动态业务逻辑,这种组合是现代 Web 开发中的最佳实践。
方案 | 本质 | 一句话总结 |
纯 Nginx | 一个高效的文件分发员 | “你要什么文件?我给你找。” |
纯 Node.js | 一个全能的JavaScript服务员 | “你的请求来了,我现给你做(执行逻辑)。” |
Nginx + Node.js | 分发员 + 专业厨师 的黄金组合 | “静态小菜(文件)我直接上,大菜(动态内容)让后面的厨师专门为你做。” |