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 小时前
十一、审计与 Run Session——每一步操作都被记录
人工智能·node.js
没事别瞎琢磨2 小时前
十六、AgentSandbox——把所有模块串起来的编排类
人工智能·node.js
没事别瞎琢磨2 小时前
十二、网络代理与白名单规则引擎
人工智能·node.js
没事别瞎琢磨2 小时前
十四、Git Worktree 隔离执行
人工智能·node.js
没事别瞎琢磨3 小时前
十、统一 Runner 入口——能力检测与模式回退
人工智能·node.js
没事别瞎琢磨4 小时前
八、环境隔离——构建安全的子进程环境
人工智能·node.js
没事别瞎琢磨5 小时前
六、输出捕获与截断
人工智能·node.js
没事别瞎琢磨5 小时前
七、敏感路径预检——Protected Paths
人工智能·node.js
没事别瞎琢磨5 小时前
五、进程执行——spawn、超时与进程树清理
人工智能·node.js
没事别瞎琢磨5 小时前
四、命令风险分级与审批策略
人工智能·node.js