Node.js系列

说说你对Node.js的理解?优缺点?应用场景?

Node.js 是一个基于 V8 引擎的 JavaScript 运行时环境,可以让 JavaScript 运行在服务器端。它采用事件驱动和非阻塞 I/O 模型,所以在处理高并发请求时性能很好。

两个特点:

1.非阻塞 I/O

Node.js 在进行数据库或文件操作时不会阻塞线程,而是把结果通过回调或 Promise 返回,所以可以同时处理很多请求。

eg:请求1 → 发起数据库请求

继续处理请求2

数据库返回结果 → 回调函数处理

2.事件驱动

Node.js 内部有事件循环机制,请求进来会放到事件队列里,当事件完成时再执行对应的回调函数。

请求进入 ->加入事件队列->Event Loop不断检查->事件完成触发回调

优点

适合高并发,适合 I/O 密集型应用,前后端都用 JavaScript,开发效率高

缺点

单线程,不适合 CPU 密集型计算,出现错误可能导致整个进程崩溃,默认不能很好利用多核 CPU

Node.js 适合:

Web API 服务,实时应用(聊天室、WebSocket),高并发系统,前端工程化工具(webpack、vite)

说说Node. js有哪些全局对象?

在浏览器中,全局对象是 window,而在 Node.js 中,全局对象是:global

Node.js 中的全局对象可以分为两类:真正的全局对象,模块级别的全局变量

真正的全局对象,这些对象在任何地方都可以直接使用。

常见的有:

global

process:是 Node 的进程对象,可以获取当前进程信息。

console

Buffer:Buffer 用来处理 二进制数据,Node.js在处理 文件流、网络数据时经常用到。

setTimeout / setInterval

clearTimeout / clearInterval

模块级别的全局变量,这些变量看起来像全局变量,但其实只在当前模块中有效。

常见的有:

__dirname:当前文件所在目录,console.log(__dirname)

__filename:当前文件完整路径

exports:用于模块导出

module

require:用于引入模块

说说对Node中的process的理解?有哪些常用方法?

process 是 Node.js 的一个全局对象,用来提供当前 Node 进程的信息,并可以对进程进行控制。

当我们执行:node index.js,实际上就是启动了一个Node进程。process 对象就代表:当前 Node 运行的这个进程

通过它可以:获取进程信息,获取环境变量,处理进程事件,进行进程控制

process.env:获取环境变量,常用于区分环境,例如:console.log(process.env.NODE_ENV)

process.argv:获取命令行参数

process.cwd():获取 当前执行目录,注意区别:process.cwd() 运行目录,__dirname:当前文件目录

process.pid:当前进程 id

process.nextTick(),让回调函数在当前事件循环结束后立即执行。

进程事件监听

process.nextTick 和 setTimeout 的区别

process.nextTick 属于微任务,优先级高于 event loop,setTimeout 属于宏任务,需要进入下一次事件循环

说说对Node中的fs模块的理解? 有哪些常用方法

fs 是 Node.js 的核心模块,用于操作文件系统。它提供了同步和异步两种 API,可以实现文件的读取、写入、追加、复制以及目录操作等功能。在实际开发中通常使用异步 API 来避免阻塞事件循环。

1 文件读取

fs.readFile(),fs.readFileSync()

fs.readFile("test.txt","utf8",(err,data)=>{console.log(data)})

2 文件写入

fs.writeFile(),fs.writeFileSync()

fs.writeFile("test.txt","hello",err=>{console.log("写入成功")})

3 文件追加

fs.appendFile(),fs.appendFileSync()

fs.appendFile("test.txt"," world",()=>{})

4 文件复制

fs.copyFile(),fs.copyFileSync()

5 目录操作

例如:fs.mkdir(),fs.rmdir(),fs.readdir()

创建目录:fs.mkdir("test",(err)=>{})

Node.js 还有 流式文件操作:

fs.createReadStream(),fs.createWriteStream()

适合处理:大文件,文件上传,视频流,因为不会一次性把文件加载到内存。

说说对Node中的Buffer的理解?应用场景?

Buffer 是 Node.js 中用于处理二进制数据的一个类,本质上是一块连续的内存空间,可以理解为一个字节数组。在 Node.js 中进行文件读取、网络传输或流式数据处理时,数据通常会以 Buffer 的形式存在。常见的创建方式有 Buffer.from() 根据数据创建 Buffer和 Buffer.alloc()创建指定大小的 Buffer。

说说对 Node 中的 Stream 的理解?应用场景?

Stream(流)是Node.js中用于处理数据流的一种机制,可以按块(chunk)逐步读取或写入数据,而不是一次性把数据全部加载到内存。因为大文件一次读入内存容易内存溢出,Node.js中的Stream分为四种:

1 可读流(Readable)用于读取数据,fs.createReadStream()

2 可写流(Writable)用于写入数据,fs.createWriteStream()

3 双工流(Duplex)既可以读又可以写,net.Socket

4 转换流(Transform)读写的同时对数据进行转换,压缩,加密,格式转换,比如:zlib

说说Node中的EventEmitter? 如何实现一个EventEmitter?

EventEmitter 是 Node.js 实现事件驱动机制的核心类,很多模块都继承自它。通过 on 方法注册事件监听,通过 emit 方法触发事件,本质上是发布订阅模式。内部通常通过一个对象保存事件和对应的回调函数,在触发事件时依次执行这些回调。

javascript 复制代码
class EventEmitter {
  constructor() {
    this.events = {}
  }

  on(type, fn) {
    if (!this.events[type]) {
      this.events[type] = []
    }
    this.events[type].push(fn)
  }

  emit(type, ...args) {
    const handlers = this.events[type]
    if (!handlers) return

    handlers.forEach(fn => fn(...args))
  }

  off(type, fn) {
    const handlers = this.events[type]
    if (!handlers) return

    this.events[type] = handlers.filter(item => item !== fn)
  }
}

说说对Nodejs中的事件循环机制理解?

Node.js 的事件循环是基于 libuv 实现的,用来处理异步任务和 I/O 操作。事件循环一共有六个阶段,分别是 timers、I/O callbacks、idle/prepare、poll、check 和 close callbacks。不同类型的任务会进入不同阶段的队列,例如 setTimeout 在 timers 阶段执行,setImmediate 在 check 阶段执行。Node 中还存在微任务机制,其中 process.nextTick 的优先级最高,其次是 Promise 的 then 回调,它们会在当前阶段结束后、进入下一个阶段之前执行。

Node.js 中的 process.nextTick 不属于事件循环的任何阶段,它会在当前阶段执行完之后、进入下一阶段之前执行,因此优先级高于 Promise 的微任务。如果在 nextTick 中不断递归调用 nextTick,就会导致事件循环无法进入下一阶段,从而造成事件循环饥饿,阻塞 I/O 和定时器任务。

setImmediate 是 Node.js 提供的一个异步 API,它会把回调函数放到事件循环的 check 阶段执行。通常用于在当前 I/O 操作完成后立即执行回调。在 I/O 回调中,setImmediate 的执行顺序会早于 setTimeout(0)。

说说Node文件查找的优先级以及Require方法的文件查找策略?

Node.js 的 require 在加载模块时会按照一定顺序查找。首先会检查模块缓存,如果缓存中存在则直接返回。其次会检查是否是 Node 的内置模块,例如 fs 或 path。如果是路径模块,则按照相对路径或绝对路径查找文件,并按 .js、.json、.node 的顺序尝试加载。如果 require 的是一个目录,则会先读取 package.json 的 main 字段,如果没有则默认加载 index.js。最后如果是第三方模块,则会从当前目录的 node_modules 开始逐级向上查找,直到根目录。

require 是 CommonJS 规范中的模块加载方式,属于运行时加载,可以动态引入模块;而 import 是 ES Module 规范中的语法,在编译阶段就确定依赖关系。require 是同步加载,而 import 支持静态分析,因此可以实现 Tree Shaking。另外 require 使用 module.exports 导出,而 import 使用 export 和 export default 导出。

说说对中间件概念的理解,如何封装node中间件?

在 Node.js Web 框架中,中间件是处理 HTTP 请求的一种机制,本质上是一个函数,它可以在请求和响应之间执行逻辑,例如日志记录、权限校验或数据解析等。像 Koa 框架中的中间件采用洋葱模型,通过 async/await 和 next 函数实现中间件的层层调用。封装中间件时通常返回一个函数 (ctx, next) => {},在函数内部处理逻辑并调用 await next() 进入下一个中间件。

如何实现jwt鉴权机制?说说你的思路

JWT 是一种基于Token的身份认证机制,由 Header、Payload 和 Signature 三部分组成。用户登录成功后,服务器会生成一个 JWT 并返回给客户端,客户端在后续请求中通过 Authorization 请求头携带该 Token。服务器通过验证 Token 的签名和有效期来判断用户身份。在 Node.js 中通常使用 jsonwebtoken 库生成和校验 Token,并通过中间件实现接口鉴权。

如何实现文件上传?说说你的思路

文件上传一般通过 input type=file 选择文件,然后用 FormData 通过 multipart/form-data 格式发送到服务器。服务端通过 multer、koa-body 等中间件解析文件,最后使用 fs 保存到服务器。如果是大文件,还可以通过 分片上传和断点续传优化。

Node性能如何进行监控以及优化?

分页一般由前端传递 page 和 pageSize,后端通过 (page - 1) * pageSize 计算 offset,然后使用 LIMIT + OFFSET 查询数据库,并返回总数、总页数以及当前页数据给前端。前端根据这些数据渲染分页组件。如果数据量很大,可以使用游标分页或索引优化提高性能。

Node性能如何进行监控以及优化?

Node 性能监控主要关注 CPU、内存、I/O 和网络等指标,可以通过 process.memoryUsage 或 Easy-Monitor、PM2 等工具进行监控。性能优化主要包括避免同步阻塞、使用 Stream 处理大文件、增加缓存减少数据库访问、优化数据库查询以及通过 cluster 或 PM2 利用多核 CPU 提高并发能力。

相关推荐
心心喵2 小时前
[linux] 本地部署网页(windows下载node.js, 安装pnpm)
node.js
Tzarevich8 小时前
从零手写一个“迷你版 Cursor”:让 AI 真正帮你写代码
langchain·node.js·agent
本末倒置18310 小时前
Bun 内置模块全解析:告别第三方依赖,提升开发效率
前端·javascript·node.js
昭昭日月明1 天前
搭建高可用私有 NPM 镜像
node.js·代码规范
七牛云行业应用2 天前
保姆级 OpenClaw 避坑指南:手把手教你看日志修 Bug,顺畅连通各大 AI 模型
人工智能·后端·node.js
多厘2 天前
使用 nvm 管理多版本 Node 项目依赖
node.js
前端双越老师3 天前
Skills 是什么?如何用于 Agent 开发?
人工智能·node.js·agent
San303 天前
AI 时代的“USB-C”接口:MCP 核心原理与实战
langchain·node.js·mcp
helloweilei5 天前
javascript 结构化克隆
javascript·node.js