面试题答案
一键面试可能遇到的性能瓶颈
- 回调地狱:在复杂业务逻辑中,多层嵌套的回调函数会使代码可读性和可维护性变差,且容易出错。
- 内存泄漏:如果异步操作没有正确处理,例如未释放资源或事件监听器未正确移除,可能导致内存占用不断增加。
- CPU 密集型任务:Node.js 单线程模型,一旦遇到 CPU 密集型任务,会阻塞事件循环,影响高并发处理能力。
- I/O 压力:虽然 Node.js 擅长处理 I/O,但在高并发下,大量 I/O 请求可能导致 I/O 设备成为瓶颈。
改进方案
- 使用 Promise 和 async/await:将回调函数转换为 Promise,利用 async/await 语法糖使异步代码更像同步代码,提高可读性和可维护性。
- 资源管理:在异步操作完成后,确保释放所有相关资源,移除不必要的事件监听器。
- 多进程/线程:对于 CPU 密集型任务,使用
child_process
模块创建子进程或worker_threads
模块创建线程来并行处理任务,避免阻塞事件循环。 - 优化 I/O:使用连接池管理数据库连接,合理设置缓冲区大小,采用异步 I/O 操作,减少 I/O 等待时间。
代码示例
- 使用 Promise 和 async/await
// 传统回调方式
function readFileCallback(filePath, callback) {
const fs = require('fs');
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
callback(err);
} else {
callback(null, data);
}
});
}
// 使用 Promise
function readFilePromise(filePath) {
return new Promise((resolve, reject) => {
const fs = require('fs');
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
// async/await 示例
async function main() {
try {
const data = await readFilePromise('example.txt');
console.log(data);
} catch (err) {
console.error(err);
}
}
main();
- 多进程处理 CPU 密集型任务
const { fork } = require('child_process');
// CPU 密集型任务函数
function cpuIntensiveTask() {
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += i;
}
return sum;
}
// 创建子进程
const child = fork('cpu - intensive - worker.js');
child.on('message', (result) => {
console.log('Result from child:', result);
});
child.send('start');
cpu - intensive - worker.js
process.on('message', (msg) => {
if (msg ==='start') {
const result = cpuIntensiveTask();
process.send(result);
}
});
function cpuIntensiveTask() {
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += i;
}
return sum;
}
- 连接池优化 I/O(以 MySQL 为例)
const mysql = require('mysql2');
// 创建连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'test',
connectionLimit: 10
});
// 使用连接池执行查询
pool.query('SELECT * FROM users', (err, results) => {
if (err) {
console.error(err);
} else {
console.log(results);
}
pool.end();
});