当前位置: 首页 > news >正文

Node.js面试题及详细答案120题(16-30) -- 核心模块篇

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 16. Node.js的核心模块有哪些?请举例说明其用途。
      • 17. `fs`模块的作用是什么?它的同步和异步方法有什么区别?
      • 18. 如何使用`fs`模块读取大文件?为什么不推荐用同步方法读取大文件?
      • 19. `path`模块的常用方法有哪些?它们的作用是什么?
      • 20. `http`模块如何创建一个简单的Web服务器?
      • 21. 如何处理`http`请求中的GET和POST参数?
        • 处理GET参数
        • 处理POST参数
      • 22. `url`模块的作用是什么?如何解析URL字符串?
      • 23. `querystring`模块如何解析查询字符串?
      • 24. `events`模块的作用是什么?如何自定义事件?
      • 25. 什么是EventEmitter?它的常用方法有哪些?
      • 26. `stream`模块的作用是什么?它有哪几种类型?
      • 27. 为什么说流(Stream)适合处理大文件?请举例说明流的使用场景。
      • 28. `buffer`模块的作用是什么?它和字符串有什么区别?
      • 29. 如何在Node.js中操作Buffer?请举例说明常用方法。
        • 1. 创建Buffer
        • 2. 读写Buffer
        • 3. 复制Buffer
        • 4. 切片Buffer
        • 5. 拼接Buffer
        • 6. 比较Buffer
      • 30. `util`模块的`util.promisify`方法有什么作用?
  • 二、120道Node.js面试题目录列表

一、本文面试题目录

16. Node.js的核心模块有哪些?请举例说明其用途。

Node.js 提供了众多核心模块,这些模块由 Node.js 官方开发,无需额外安装即可使用,主要用于处理文件、网络、事件等基础功能。以下是常用核心模块及其用途:

  • fs:文件系统模块,用于读写文件、操作目录等(如 fs.readFile 读取文件,fs.writeFile 写入文件)。
  • path:路径处理模块,用于解析和拼接文件路径(如 path.join 拼接路径,path.resolve 获取绝对路径)。
  • http:HTTP 协议模块,用于创建 Web 服务器和客户端(如 http.createServer 创建服务器)。
  • https:HTTPS 协议模块,功能类似 http,但支持加密传输。
  • url:URL 解析模块,用于解析 URL 字符串(如 url.parse 解析 URL 为对象)。
  • querystring:查询字符串模块,用于解析和序列化 URL 中的查询参数(如 querystring.parse 解析查询字符串)。
  • events:事件处理模块,提供事件触发和监听机制(核心是 EventEmitter 类)。
  • stream:流模块,用于处理流式数据(如文件流、网络流),适合大文件处理。
  • buffer:缓冲区模块,用于处理二进制数据(如网络传输、文件读写中的二进制数据)。
  • util:工具模块,提供实用工具函数(如 util.promisify 将回调函数转为 Promise)。
  • os:操作系统模块,用于获取系统信息(如 os.cpus 获取 CPU 信息,os.totalmem 获取总内存)。
  • process:进程模块,提供当前 Node.js 进程的信息和控制方法(如 process.env 环境变量,process.exit 退出进程)。

示例:使用多个核心模块

const fs = require('fs');
const path = require('path');
const os = require('os');// 读取当前目录下的文件
const filePath = path.join(__dirname, 'example.txt');
fs.readFile(filePath, 'utf8', (err, data) => {if (err) throw err;console.log('文件内容:', data);
});// 输出系统信息
console.log('CPU 核心数:', os.cpus().length);
console.log('总内存(GB):', os.totalmem() / (1024 **3).toFixed(2));

17. fs模块的作用是什么?它的同步和异步方法有什么区别?

fs(File System)模块是 Node.js 用于与文件系统交互的核心模块,提供了文件读写、目录操作、权限管理等功能。它的方法分为同步异步两种形式。

同步方法与异步方法的区别

区别同步方法异步方法
执行方式阻塞主线程,需等待操作完成后才继续执行非阻塞主线程,操作在后台执行,完成后通过回调通知
命名规则方法名末尾加 Sync(如 readFileSync方法名无特殊后缀(如 readFile
错误处理通过 try/catch 捕获错误通过回调函数的第一个参数返回错误
返回值直接返回操作结果结果通过回调函数的参数返回
适用场景简单脚本、初始化操作(不影响并发的场景)服务器环境、高并发场景(避免阻塞主线程)

示例:同步与异步读取文件

const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'test.txt');// 同步读取
try {const data = fs.readFileSync(filePath, 'utf8');console.log('同步读取结果:', data);
} catch (err) {console.error('同步读取错误:', err);
}// 异步读取
fs.readFile(filePath, 'utf8', (err, data) => {if (err) {console.error('异步读取错误:', err);return;}console.log('异步读取结果:', data);
});

18. 如何使用fs模块读取大文件?为什么不推荐用同步方法读取大文件?

读取大文件(如几个 GB 的文件)时,不适合一次性将文件内容加载到内存中,而应使用流(Stream) 进行分块读取,以降低内存占用。

使用流读取大文件的示例

const fs = require('fs');
const path = require('path');const largeFilePath = path.join(__dirname, 'large-file.txt');// 创建可读流
const readStream = fs.createReadStream(largeFilePath, {encoding: 'utf8',  // 编码格式highWaterMark: 64 * 1024  // 每次读取的缓冲区大小(默认64KB)
});// 监听数据事件(每读取一块数据触发)
readStream.on('data', (chunk) => {console.log(`读取到 ${chunk.length} 字节的数据`);// 处理数据(如解析、过滤等)
});// 监听结束事件
readStream.on('end', () => {console.log('文件读取完成');
});// 监听错误事件
readStream.on('error', (err) => {console.error('读取错误:', err);
});

不推荐用同步方法读取大文件的原因
1.** 阻塞主线程 :同步方法(如 readFileSync)会阻塞 Node.js 主线程,直到文件读取完成,期间无法处理其他请求,严重影响应用的并发能力。
2.
内存占用过高 :同步方法会将整个文件内容加载到内存中,大文件可能导致内存溢出(OOM),使应用崩溃。
3.
性能低下**:一次性读取大文件需要分配大量内存,且数据处理效率低,而流的分块处理更轻量、高效。

19. path模块的常用方法有哪些?它们的作用是什么?

path 模块用于处理文件路径,解决不同操作系统(如 Windows 和 Linux)路径分隔符差异(\/)的问题,提供了跨平台的路径处理能力。

常用方法及作用

  1. path.join([...paths])

    • 拼接多个路径片段,自动处理分隔符,返回规范化的路径。
    path.join('/a', 'b', 'c'); // 输出:'/a/b/c'
    path.join('/a', '../b');   // 输出:'/b'(解析上层目录)
    
  2. path.resolve([...paths])

    • 将路径片段解析为绝对路径,以当前工作目录为基准。
    path.resolve('file.txt');        // 输出:'/当前工作目录/file.txt'
    path.resolve('/a', 'b', '../c'); // 输出:'/a/c'
    
  3. path.basename(path[, ext])

    • 返回路径中的文件名(包含扩展名),可选参数 ext 可去除扩展名。
    path.basename('/a/b/c.txt');   // 输出:'c.txt'
    path.basename('/a/b/c.txt', '.txt'); // 输出:'c'
    
  4. path.dirname(path)

    • 返回路径中的目录部分。
    path.dirname('/a/b/c.txt'); // 输出:'/a/b'
    
  5. path.extname(path)

    • 返回路径中的文件扩展名(包含 .),无扩展名则返回空字符串。
    path.extname('file.txt');   // 输出:'.txt'
    path.extname('file');       // 输出:''
    path.extname('file.md.txt');// 输出:'.txt'
    
  6. path.parse(path)

    • 将路径解析为包含 rootdirbasenameext 的对象。
    path.parse('/a/b/c.txt');
    // 输出:
    // {
    //   root: '/',
    //   dir: '/a/b',
    //   base: 'c.txt',
    //   name: 'c',
    //   ext: '.txt'
    // }
    
  7. path.format(pathObject)

    • path.parse 生成的对象转换为路径字符串。
    path.format({ dir: '/a/b', base: 'c.txt' }); // 输出:'/a/b/c.txt'
    

示例:综合使用 path 模块

const path = require('path');const filePath = '/user/docs/report.pdf';console.log('文件名:', path.basename(filePath)); // 'report.pdf'
console.log('目录:', path.dirname(filePath));   // '/user/docs'
console.log('扩展名:', path.extname(filePath)); // '.pdf'
console.log('拼接路径:', path.join(path.dirname(filePath), 'archive', 'old.pdf')); 
// '/user/docs/archive/old.pdf'

20. http模块如何创建一个简单的Web服务器?

http 模块是 Node.js 用于构建 HTTP 服务器和客户端的核心模块,通过 http.createServer() 方法可快速创建 Web 服务器。

创建简单Web服务器的步骤

  1. 引入 http 模块。
  2. 使用 http.createServer() 创建服务器实例,传入请求处理函数(接收 req 请求对象和 res 响应对象)。
  3. 调用 server.listen() 方法指定端口和主机,启动服务器。

示例

const http = require('http');// 创建服务器
const server = http.createServer((req, res) => {// 设置响应头(状态码 200,内容类型为文本)res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });// 根据 URL 路径返回不同内容if (req.url === '/') {res.end('欢迎访问首页!\n');} else if (req.url === '/about') {res.end('关于我们\n');} else {res.writeHead(404, { 'Content-Type': 'text/plain' });res.end('404 页面未找到\n');}
});// 启动服务器,监听 3000 端口
const PORT = 3000;
server.listen(PORT, 'localhost', () => {console.log(`服务器运行在 http://localhost:${PORT}`);
});

关键对象说明

  • req(IncomingMessage):请求对象,包含请求方法、URL、头信息等(如 req.methodreq.url)。
  • res(ServerResponse):响应对象,用于发送响应(如 res.writeHead() 设置响应头,res.end() 发送响应体并结束响应)。

运行上述代码后,访问 http://localhost:3000 可看到首页内容,访问 http://localhost:3000/about 可看到关于页面。

21. 如何处理http请求中的GET和POST参数?

在 Node.js 的 http 模块中,GET 和 POST 参数的处理方式不同:GET 参数位于 URL 中,POST 参数位于请求体中。

处理GET参数

GET 参数通过 URL 的查询字符串(?key=value&key2=value2)传递,可使用 url 模块或 querystring 模块解析。

示例

const http = require('http');
const url = require('url');
const querystring = require('querystring');const server = http.createServer((req, res) => {if (req.method === 'GET') {// 解析 URL(第二个参数为 true 时自动解析 query 为对象)const parsedUrl = url.parse(req.url, true);const query = parsedUrl.query; // 获取 GET 参数对象res.writeHead(200, { 'Content-Type': 'application/json' });res.end(JSON.stringify({message: 'GET 请求参数',params: query}));}
});server.listen(3000, () => {console.log('服务器运行在 http://localhost:3000');
});

访问 http://localhost:3000?name=Alice&age=20,将返回解析后的 GET 参数。

处理POST参数

POST 参数位于请求体中,需通过监听 req 对象的 data 事件(接收数据块)和 end 事件(数据接收完成)来获取,再用 querystring 解析。

示例

const http = require('http');
const querystring = require('querystring');const server = http.createServer((req, res) => {if (req.method === 'POST') {let body = '';// 接收数据块req.on('data', (chunk) => {body += chunk;});// 数据接收完成req.on('end', () => {// 解析 POST 参数(默认解析 form-data 格式)const postData = querystring.parse(body);res.writeHead(200, { 'Content-Type': 'application/json' });res.end(JSON.stringify({message: 'POST 请求参数',params: postData}));});}
});server.listen(3000, () => {console.log('服务器运行在 http://localhost:3000');
});

可通过 POST 工具(如 Postman)发送 name=Bob&age=25 表单数据,服务器将返回解析结果。

注意:对于 JSON 格式的 POST 数据(如 {"name":"Bob"}),需手动解析:

// 在 end 事件中
const postData = JSON.parse(body); // 适用于 Content-Type: application/json

22. url模块的作用是什么?如何解析URL字符串?

url 模块用于处理 URL 字符串,提供了解析 URL、格式化 URL 等功能,可将 URL 字符串转换为对象(便于获取各部分信息),或反之。

主要作用

  • 解析 URL 字符串为对象,提取协议、主机、路径、查询参数等部分。
  • 将 URL 对象格式化为 URL 字符串。
  • 处理不同格式的 URL(如绝对 URL、相对 URL)。

解析URL字符串的方法
使用 url.parse(urlString[, parseQueryString[, slashesDenoteHost]]) 方法:

  • urlString:要解析的 URL 字符串。
  • parseQueryString:可选,默认为 false,若为 true,则将查询字符串解析为对象。
  • slashesDenoteHost:可选,默认为 false,用于处理无协议的 URL。

示例

const url = require('url');const urlString = 'https://user:pass@example.com:8080/path?name=Alice&age=20#hash';// 解析 URL(parseQueryString 设为 true,自动解析查询参数)
const parsedUrl = url.parse(urlString, true);console.log('解析结果:', parsedUrl);
/* 输出主要属性:
{protocol: 'https:',        // 协议auth: 'user:pass',         // 用户名:密码host: 'example.com:8080',  // 主机名:端口hostname: 'example.com',   // 主机名port: '8080',              // 端口pathname: '/path',         // 路径search: '?name=Alice&age=20', // 查询字符串(含?)query: { name: 'Alice', age: '20' }, // 解析后的查询参数对象hash: '#hash'              // 哈希(含#)
}
*/// 将 URL 对象转换为字符串
const formattedUrl = url.format(parsedUrl);
console.log('格式化结果:', formattedUrl); // 输出原始 URL 字符串

注意:Node.js v11.0.0 后推荐使用 WHATWG URL 标准 API(new URL(urlString)),功能更完善:

const myUrl = new URL('https://example.com/path?name=Alice');
console.log(myUrl.searchParams.get('name')); // 'Alice'(获取查询参数)

23. querystring模块如何解析查询字符串?

querystring 模块用于处理 URL 中的查询字符串(如 name=Alice&age=20),提供了解析(字符串转对象)和序列化(对象转字符串)功能。

常用方法

  1. querystring.parse(str[, sep[, eq[, options]]])

    • 解析查询字符串为对象。
    • str:要解析的查询字符串。
    • sep:分隔符,默认为 &
    • eq:键值分隔符,默认为 =
    • options:可选配置(如 maxKeys 限制解析的键数量)。

    示例

    const querystring = require('querystring');const str = 'name=Alice&age=20&hobby=reading&hobby=sports';
    const obj = querystring.parse(str);
    console.log(obj);
    // 输出:{ name: 'Alice', age: '20', hobby: [ 'reading', 'sports' ] }
    
  2. querystring.stringify(obj[, sep[, eq[, options]]])

    • 将对象序列化为查询字符串。
    • obj:要序列化的对象。
    • sep:分隔符,默认为 &
    • eq:键值分隔符,默认为 =

    示例

    const querystring = require('querystring');const obj = { name: 'Bob', age: 25, hobby: ['music', 'games'] };
    const str = querystring.stringify(obj);
    console.log(str);
    // 输出:'name=Bob&age=25&hobby=music&hobby=games'
    
  3. querystring.escape(str)

    • 对字符串进行 URL 编码(将特殊字符转换为 %xx 格式)。
    querystring.escape('a b=c'); // 输出:'a%20b%3Dc'
    
  4. querystring.unescape(str)

    • 对 URL 编码的字符串进行解码。
    querystring.unescape('a%20b%3Dc'); // 输出:'a b=c'
    

注意querystring 适合解析简单的查询字符串,对于复杂场景(如嵌套对象),建议使用 qs 等第三方库。

24. events模块的作用是什么?如何自定义事件?

events 模块是 Node.js 实现事件驱动架构的核心,提供了事件的触发、监听、移除等功能,其核心是 EventEmitter 类。

主要作用

  • 实现对象间的事件通信(发布-订阅模式)。
  • 支持自定义事件,通过触发事件执行回调函数。
  • 是许多 Node.js 核心模块(如 fshttp)的基础(这些模块的对象继承自 EventEmitter)。

自定义事件的步骤

  1. 引入 events 模块,创建 EventEmitter 实例。
  2. 使用 on()addListener() 方法监听事件。
  3. 使用 emit() 方法触发事件,可传递参数。

示例

const EventEmitter = require('events');// 创建 EventEmitter 实例
const myEmitter = new EventEmitter();// 监听 'greet' 事件(第一个参数为事件名,第二个为回调函数)
myEmitter.on('greet', (name) => {console.log(`Hello, ${name}!`);
});// 监听 'sum' 事件,处理数字相加
myEmitter.on('sum', (a, b) => {console.log(`${a} + ${b} = ${a + b}`);
});// 触发事件(第一个参数为事件名,后续为传递给回调的参数)
myEmitter.emit('greet', 'Alice'); // 输出:Hello, Alice!
myEmitter.emit('sum', 3, 5);      // 输出:3 + 5 = 8// 一次性事件(触发后自动移除)
myEmitter.once('single', () => {console.log('这个事件只会触发一次');
});
myEmitter.emit('single'); // 输出:这个事件只会触发一次
myEmitter.emit('single'); // 无输出(事件已移除)

注意EventEmitter 有默认的事件监听器数量限制(默认 10 个),超过时会触发警告,可通过 setMaxListeners(n) 调整。

25. 什么是EventEmitter?它的常用方法有哪些?

EventEmitterevents 模块提供的一个类,是 Node.js 事件驱动模型的核心,用于实现事件的发布(触发)和订阅(监听)。Node.js 中的许多核心对象(如 http.Serverfs.ReadStream)都继承自 EventEmitter

常用方法

  1. on(eventName, listener)

    • 为指定事件注册一个监听器(回调函数),可多次调用注册多个监听器。
    emitter.on('data', (chunk) => { console.log(chunk); });
    
  2. emit(eventName[, ...args])

    • 触发指定事件,可传递多个参数给监听器。返回 true 表示事件有监听器,否则为 false
    emitter.emit('data', 'hello'); // 触发 'data' 事件,传递 'hello'
    
  3. once(eventName, listener)

    • 为指定事件注册一个一次性监听器,触发一次后自动移除。
    emitter.once('init', () => { console.log('初始化完成'); });
    
  4. off(eventName, listener)(或 removeListener):

    • 移除指定事件的某个监听器(需传入监听器的引用)。
    const listener = () => { console.log('监听'); };
    emitter.on('event', listener);
    emitter.off('event', listener); // 移除监听器
    
  5. removeAllListeners([eventName])

    • 移除指定事件的所有监听器,若未指定事件名,则移除所有事件的监听器。
    emitter.removeAllListeners('data'); // 移除 'data' 事件的所有监听器
    
  6. setMaxListeners(n)

    • 设置事件监听器的最大数量(默认 10 个),超过时的警告可通过此方法关闭(设为 Infinity)。
    emitter.setMaxListeners(20); // 允许最多 20 个监听器
    
  7. listeners(eventName)

    • 返回指定事件的所有监听器数组。
    console.log(emitter.listeners('data')); // 输出 'data' 事件的监听器数组
    

示例:综合使用 EventEmitter 方法

const EventEmitter = require('events');
const emitter = new EventEmitter();// 定义监听器函数
const logMessage = (msg) => {console.log('收到消息:', msg);
};// 注册监听器
emitter.on('message', logMessage);
emitter.on('message', (msg) => {console.log('消息长度:', msg.length);
});// 触发事件
emitter.emit('message', 'Hello EventEmitter');
// 输出:
// 收到消息: Hello EventEmitter
// 消息长度: 18// 移除监听器
emitter.off('message', logMessage);
emitter.emit('message', '再次发送');
// 输出:
// 消息长度: 4

26. stream模块的作用是什么?它有哪几种类型?

stream(流)模块是 Node.js 用于处理流式数据的核心模块,通过分块读取/写入数据,降低内存占用,提高处理效率,尤其适合大文件或持续的数据流(如网络传输)。

主要作用

  • 分块处理数据,避免一次性加载大量数据到内存。
  • 支持管道(pipe)操作,可将一个流的输出直接作为另一个流的输入(如文件压缩、网络传输)。
  • 提供统一的接口处理不同类型的数据流(文件、网络、内存等)。

流的四种类型

  1. Readable(可读流)

    • 用于读取数据的流(如 fs.createReadStream 读取文件)。
    • 状态:paused(暂停)和 flowing(流动),数据通过 data 事件传递。
  2. Writable(可写流)

    • 用于写入数据的流(如 fs.createWriteStream 写入文件)。
    • 通过 write() 方法写入数据,end() 方法结束写入。
  3. Duplex(双工流)

    • 同时具备可读和可写能力的流(如 TCP 套接字 net.Socket)。
    • 可读和可写部分相互独立,分别遵循各自的接口。
  4. Transform(转换流)

    • 一种特殊的双工流,用于修改或转换数据(如 zlib.createGzip 压缩数据)。
    • 读取数据后进行处理,再输出处理后的结果。

示例:使用可读流和可写流复制文件

const fs = require('fs');
const path = require('path');// 创建可读流(源文件)
const readStream = fs.createReadStream(path.join(__dirname, 'source.txt'));
// 创建可写流(目标文件)
const writeStream = fs.createWriteStream(path.join(__dirname, 'copy.txt'));// 监听数据事件,将读取的块写入可写流
readStream.on('data', (chunk) => {writeStream.write(chunk);
});// 读取完成后结束写入
readStream.on('end', () => {writeStream.end();console.log('文件复制完成');
});// 简化写法:使用 pipe 自动处理数据传递
// readStream.pipe(writeStream);

27. 为什么说流(Stream)适合处理大文件?请举例说明流的使用场景。

流(Stream)适合处理大文件的核心原因是其分块处理数据的特性,无需将整个文件加载到内存中,而是逐块读取、处理和写入,显著降低内存占用并提高效率。

流适合处理大文件的原因

  1. 低内存占用:大文件(如 10GB)无法一次性加载到内存,流通过每次读取一小块数据(默认 64KB),内存占用保持稳定。
  2. 高效处理:数据可边读取边处理(如解析、过滤),无需等待整个文件加载完成,减少处理延迟。
  3. 管道操作:支持 pipe() 方法将多个流串联(如读取 → 压缩 → 写入),简化大文件处理流程。

流的典型使用场景

1.** 大文件复制 **:

const fs = require('fs');
// 使用 pipe 快速复制大文件
fs.createReadStream('large-file.iso').pipe(fs.createWriteStream('copy-large-file.iso'));

2.** 日志实时处理 **:
监听日志文件的新增内容并实时分析(如监控系统)。

const fs = require('fs');
const readStream = fs.createReadStream('app.log', { tail: true }); // 模拟尾行监听
readStream.on('data', (chunk) => {console.log('新日志:', chunk.toString());// 实时分析逻辑(如错误检测)
});

3.** 数据压缩/解压 **:
结合 zlib 模块对流数据进行压缩(无需加载整个文件到内存)。

const fs = require('fs');
const zlib = require('zlib');
// 读取文件 → 压缩 → 写入压缩文件
fs.createReadStream('large-file.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('large-file.txt.gz'));

4.** 网络数据传输 **:
HTTP 服务器中通过流发送大文件(如视频、下载资源)。

const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {if (req.url === '/video') {res.writeHead(200, { 'Content-Type': 'video/mp4' });// 以流的形式发送视频文件fs.createReadStream('large-video.mp4').pipe(res);}
}).listen(3000);

5.** 数据转换 **:
处理 CSV 大文件并转换为 JSON 格式。

const fs = require('fs');
const readline = require('readline'); // 逐行读取流
const rl = readline.createInterface({input: fs.createReadStream('large-data.csv'),crlfDelay: Infinity
});
rl.on('line', (line) => {// 每行转换为 JSON 并处理const json = convertCsvToJson(line);console.log(json);
});

28. buffer模块的作用是什么?它和字符串有什么区别?

buffer 模块是 Node.js 用于处理二进制数据的核心模块,提供了 Buffer 类(无需 require 即可使用),用于存储和操作二进制数据。在处理文件、网络传输、加密等场景中,二进制数据是基础,Buffer 解决了 JavaScript 原生不支持二进制数据的问题。

Buffer 与字符串的区别

区别Buffer字符串(String)
数据类型二进制数据(字节序列)Unicode 字符序列(文本数据)
编码方式可通过编码(如 utf8base64)转换为字符串本质是 Unicode 编码,可通过 Buffer.from() 转为 Buffer
长度计算length 属性返回字节数length 属性返回字符数(可能与字节数不同)
不可变性长度固定,内容可修改(内存分配后大小不变)不可变,修改会创建新字符串
适用场景二进制数据(文件、网络、加密)文本数据(用户输入、显示内容)

示例:Buffer 与字符串的转换

// 字符串转 Buffer(默认 utf8 编码)
const str = 'Hello 世界';
const buf = Buffer.from(str);
console.log('Buffer 内容:', buf); // <Buffer 48 65 6c 6c 6f 20 e4 b8 96 e7 95 8c>
console.log('Buffer 字节数:', buf.length); // 11('Hello ' 占 6 字节,'世界' 占 6 字节?此处实际为11字节,因UTF8编码中汉字占3字节)// Buffer 转字符串
const str2 = buf.toString('utf8');
console.log('转换后的字符串:', str2); // 'Hello 世界'// 不同编码的转换
const base64Str = buf.toString('base64');
console.log('Base64 编码:', base64Str); // 'SGVsbG8g5LiW55WM'
const buf2 = Buffer.from(base64Str, 'base64');
console.log(buf2.toString('utf8')); // 'Hello 世界'

注意:字符串的 length 可能与对应的 Buffer 字节数不同(如中文在 UTF8 中占 3 字节),例如 '世界'.length 为 2,而 Buffer.from('世界').length 为 6。

29. 如何在Node.js中操作Buffer?请举例说明常用方法。

Buffer 是 Node.js 中处理二进制数据的核心类,提供了丰富的方法用于创建、读写、转换 Buffer。以下是常用操作及示例:

1. 创建Buffer
  • Buffer.alloc(size):创建指定大小的空 Buffer(已初始化,默认填充 0)。
  • Buffer.allocUnsafe(size):创建指定大小的 Buffer(未初始化,可能包含旧数据,速度更快)。
  • Buffer.from(data):从数据(字符串、数组、Buffer 等)创建 Buffer。
// 创建 10 字节的空 Buffer
const buf1 = Buffer.alloc(10);
console.log(buf1); // <Buffer 00 00 00 00 00 00 00 00 00 00>// 从字符串创建 Buffer
const buf2 = Buffer.from('hello');
console.log(buf2); // <Buffer 68 65 6c 6c 6f>// 从数组创建 Buffer(数组元素为 0-255 的整数)
const buf3 = Buffer.from([0x68, 0x65, 0x6c]); // 对应 'hel'
console.log(buf3.toString()); // 'hel'
2. 读写Buffer

Buffer 可通过索引读写字节(0-255 的整数)。

const buf = Buffer.alloc(4);// 写入字节
buf[0] = 0x48; // 'H' 的 ASCII 码
buf[1] = 0x65; // 'e'
buf[2] = 0x6c; // 'l'
buf[3] = 0x6c; // 'l'console.log(buf.toString()); // 'Hell'// 读取字节
console.log(buf[0]); // 72(0x48 的十进制)
console.log(String.fromCharCode(buf[0])); // 'H'
3. 复制Buffer

buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]]):复制一个 Buffer 的内容到另一个 Buffer。

const srcBuf = Buffer.from('hello');
const destBuf = Buffer.alloc(5);srcBuf.copy(destBuf); // 复制整个 srcBuf 到 destBuf
console.log(destBuf.toString()); // 'hello'// 部分复制(复制 'llo' 到 destBuf 的起始位置 2)
const destBuf2 = Buffer.alloc(5, 'he'); // 初始化为 'he'
srcBuf.copy(destBuf2, 2, 2, 5); // targetStart=2, sourceStart=2, sourceEnd=5
console.log(destBuf2.toString()); // 'hello'
4. 切片Buffer

buf.slice([start[, end]]):返回 Buffer 的一部分(与原 Buffer 共享内存,修改会影响原 Buffer)。

const buf = Buffer.from('hello world');
const slice = buf.slice(6, 11); // 从索引 6 到 10(不包含11)
console.log(slice.toString()); // 'world'// 修改切片会影响原 Buffer
slice[0] = 0x57; // 'W' 的 ASCII 码
console.log(buf.toString()); // 'hello World'
5. 拼接Buffer

Buffer.concat(list[, totalLength]):拼接多个 Buffer 为一个新 Buffer。

const buf1 = Buffer.from('Hello ');
const buf2 = Buffer.from('World');
const combined = Buffer.concat([buf1, buf2]);
console.log(combined.toString()); // 'Hello World'
6. 比较Buffer

buf.compare(otherBuffer):比较两个 Buffer,返回数值(-1:当前小,0:相等,1:当前大)。

const buf1 = Buffer.from('abc');
const buf2 = Buffer.from('abd');
console.log(buf1.compare(buf2)); // -1('abc' < 'abd')

30. util模块的util.promisify方法有什么作用?

util.promisify 是 Node.js util 模块提供的工具函数,用于将遵循 Node.js 回调风格(即最后一个参数为回调函数,且回调的第一个参数为错误对象)的函数转换为返回 Promise 的函数,便于使用 async/await 语法处理异步操作。

作用

  • 简化异步代码,将回调地狱(Callback Hell)转换为更易读的 async/await 形式。
  • 统一异步编程风格,兼容 Promise 生态。

使用条件
被转换的函数必须符合 Node.js 回调规范:

  • 函数的最后一个参数是回调函数。
  • 回调函数的第一个参数是错误对象(err),后续参数是结果。

示例:将回调风格的函数转为 Promise

const util = require('util');
const fs = require('fs');// 回调风格的函数(fs.readFile)
fs.readFile('example.txt', 'utf8', (err, data) => {if (err) throw err;console.log('回调方式读取:', data);
});// 使用 util.promisify 转换为 Promise 风格
const readFileAsync = util.promisify(fs.readFile);// 使用 Promise.then()
readFileAsync('example.txt', 'utf8').then(data => console.log('Promise 方式读取:', data)).catch(err => console.error('错误:', err));// 使用 async/await(更简洁)
async function readFile() {try {const data = await readFileAsync('example.txt', 'utf8');console.log('async/await 方式读取:', data);} catch (err) {console.error('错误:', err);}
}
readFile();

自定义回调函数的转换

const util = require('util');// 自定义回调风格函数(符合规范)
function fetchData(callback) {setTimeout(() => {const err = null;const data = '模拟数据';callback(err, data); // 第一个参数为 err,第二个为结果}, 1000);
}// 转换为 Promise 函数
const fetchDataAsync = util.promisify(fetchData);// 使用 async/await
async function main() {const data = await fetchDataAsync();console.log(data); // '模拟数据'
}
main();

注意:Node.js v10.0.0 后,许多核心模块提供了内置的 Promise 版本(如 fs.promises),可直接使用,无需手动转换。

二、120道Node.js面试题目录列表

文章序号Node.js面试题120道
1Node.js面试题及详细答案120道(01-15)
2Node.js面试题及详细答案120道(16-30)
3Node.js面试题及详细答案120道(31-42)
4Node.js面试题及详细答案120道(43-55)
5Node.js面试题及详细答案120道(56-68)
6Node.js面试题及详细答案120道(69-80)
7Node.js面试题及详细答案120道(81-92)
8Node.js面试题及详细答案120道(93-100)
9Node.js面试题及详细答案120道(101-110)
10Node.js面试题及详细答案120道(111-120)
http://www.lryc.cn/news/619501.html

相关文章:

  • Docker部署 Neo4j 及集成 APOC 插件:安装与配置完整指南(docker-compose)
  • 数据挖掘常用公开数据集
  • spring gateway配合nacos实现负载均衡
  • 【HTML】在页面中画一条0.5px的线
  • 【Part 4 未来趋势与技术展望】第一节|技术上的抉择:三维实时渲染与VR全景视频的共生
  • SQL语句优化
  • JsonReader:Spring AI 的 JSON 搬运大师
  • html img标签设置默认图片,防止图片路径不存在导致图片不展示影响页面美观
  • 2022 年全国硕士研究生招生考试真题笔记
  • Nestjs框架: 由权限模型设计到 Prisma 数据库迁移的演示
  • ZED 2i相机调试
  • 【SpringBoot】12 核心功能-配置文件详解:Properties与YAML配置文件
  • 肖臻《区块链技术与应用》第十一讲:比特币核心概念重温:一文读懂私钥、交易、挖矿与网络现状
  • 模型驱动的自动驾驶AI系统全生命周期安全保障
  • Easysearch 数据迁移之 INFINI Gateway
  • elasticsearch mapping和template解析(自动分词)!
  • LeetCode 刷题【40. 组合总和 II】
  • Linux系统编程Day13 -- 程序地址空间(进阶)
  • 边缘节点 DDoS 防护:CDN 节点的流量清洗与就近拦截方案
  • IPA1299至为芯替代TI ADS1299的脑机接口芯片
  • 机器翻译:学习率调度详解
  • 云蝠智能 VoiceAgent 在不良资产处理中的技术应用与实践
  • 2020/12 JLPT听力原文 问题一 5番
  • 磁悬浮轴承转子动平衡:零接触旋转下的“隐形杀手”深度解析与精准猎杀指南
  • Video_AVI_Packet(1)
  • 部署 Docker 应用详解(MySQL + Tomcat + Nginx + Redis)
  • 1688商品数据抓取:Python爬虫+动态页面解析
  • Visual Studio Code 跨平台快捷键指南:Windows 与 macOS 全面对比
  • VS2022+QT5.15.2+OCCT7.9.1的开发环境搭建流程
  • vscode远程服务器出现一直卡在正在打开远程和连接超时解决办法