Node.js 面试题
事件驱动模型
概念解释:
Node.js 使用事件驱动的非阻塞 I/O 模型
通过 EventEmitter 类实现事件的发布订阅
异步操作通过回调函数或 Promise 处理
// 1. EventEmitter 基本使用
const EventEmitter = require("events");
class MyEmitter extends EventEmitter {
constructor() {
super();
// 限制最大监听器数量
this.setMaxListeners(20);
}
}
const myEmitter = new MyEmitter();
// 注册事件监听器
myEmitter.on("event", (data) => {
console.log("事件被触发:", data);
});
// 只监听一次
myEmitter.once("oneTimeEvent", () => {
console.log("这个事件只会触发一次");
});
// 触发事件
myEmitter.emit("event", { message: "Hello" });
// 2. 自定义事件流
class DatabaseEmitter extends EventEmitter {
query(sql) {
// 模拟数据库查询
this.emit("query", sql);
setTimeout(() => {
if (Math.random() > 0.5) {
this.emit("success", { rows: [] });
} else {
this.emit("error", new Error("查询失败"));
}
}, 100);
}
}
const db = new DatabaseEmitter();
db.on("query", (sql) => console.log("执行查询:", sql));
db.on("success", (result) => console.log("查询成功:", result));
db.on("error", (err) => console.error("查询错误:", err));
Stream 流操作
概念解释:
Stream 是处理流式数据的抽象接口
可以处理大文件,避免内存溢出
分为:Readable、Writable、Duplex、Transform
// 1. 文件流操作
const fs = require("fs");
// 读取流
const readStream = fs.createReadStream("big-file.txt", {
highWaterMark: 64 * 1024, // 64KB chunks
});
// 写入流
const writeStream = fs.createWriteStream("output.txt");
// 管道操作
readStream.pipe(writeStream);
// 事件处理
readStream.on("data", (chunk) => {
console.log("接收到数据:", chunk.length);
});
readStream.on("end", () => {
console.log("读取完成");
});
// 2. 自定义转换流
const { Transform } = require("stream");
class UppercaseTransform extends Transform {
_transform(chunk, encoding, callback) {
// 转换为大写
this.push(chunk.toString().toUpperCase());
callback();
}
}
const uppercaseTransform = new UppercaseTransform();
readStream.pipe(uppercaseTransform).pipe(writeStream);
// 3. 流的错误处理
readStream.on("error", (err) => {
console.error("读取错误:", err);
});
writeStream.on("error", (err) => {
console.error("写入错误:", err);
});
// 4. 背压(Backpressure)处理
const writeable = fs.createWriteStream("output.txt");
function write(data, cb) {
if (!writeable.write(data)) {
writeable.once("drain", cb);
} else {
process.nextTick(cb);
}
}
Buffer 的使用
概念解释:
Buffer 用于处理二进制数据
在内存中分配固定大小的空间
常用于文件操作和网络通信
// 1. 创建 Buffer
// 分配指定大小的 Buffer
const buf1 = Buffer.alloc(10);
// 创建包含数据的 Buffer
const buf2 = Buffer.from("Hello World");
// 不安全的分配(可能包含旧数据)
const buf3 = Buffer.allocUnsafe(10);
// 2. Buffer 操作
// 写入数据
buf1.write("Hello");
// 读取数据
console.log(buf1.toString()); // Hello
// 复制 Buffer
const bufCopy = Buffer.alloc(buf2.length);
buf2.copy(bufCopy);
// 3. Buffer 转换
// 字符串转 Buffer
const strBuf = Buffer.from("你好", "utf8");
// Buffer 转字符串
console.log(strBuf.toString("utf8")); // 你好
// 4. Buffer 拼接
const chunks = [];
let totalLength = 0;
// 收集数据块
readStream.on("data", (chunk) => {
chunks.push(chunk);
totalLength += chunk.length;
});
// 拼接完整数据
readStream.on("end", () => {
const result = Buffer.concat(chunks, totalLength);
console.log(result.toString());
});
最后更新于
这有帮助吗?