Node.js 回调函数
回调函数是 Node.js 异步编程的基础,作为参数传入函数,在操作完成后被调用。
什么是回调函数
JavaScript
// 回调函数:作为参数传入,完成后调用
function fetchData(callback) {
setTimeout(() => {
callback('数据');
}, 1000);
}
fetchData((data) => {
console.log('收到:', data);
});
同步回调与异步回调
同步回调
JavaScript
// 同步执行,立即调用
const arr = [1, 2, 3];
arr.forEach((item) => {
console.log(item); // 同步执行
});
异步回调
JavaScript
// 异步执行,稍后调用
setTimeout(() => {
console.log('延迟执行'); // 异步执行
}, 1000);
Error-First 规范
Node.js 回调遵循"错误优先"原则:
JavaScript
// 回调函数第一个参数是错误对象
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error('错误:', err.message);
return;
}
console.log('数据:', data);
});
// 自定义异步函数
function asyncOperation(callback) {
doSomething((result, error) => {
if (error) {
callback(error); // 错误作为第一个参数
} else {
callback(null, result); // 成功时第一个参数为 null
}
});
}
回调地狱问题
JavaScript
// 多层嵌套导致代码难以阅读
fs.readFile('file1.txt', 'utf8', (err1, data1) => {
if (err1) throw err1;
fs.readFile('file2.txt', 'utf8', (err2, data2) => {
if (err2) throw err2;
fs.readFile('file3.txt', 'utf8', (err3, data3) => {
if (err3) throw err3;
fs.writeFile('output.txt', data1 + data2 + data3, (err4) => {
if (err4) throw err4;
console.log('完成');
});
});
});
});
解决回调地狱
拆分函数
JavaScript
function readFiles(callback) {
fs.readFile('file1.txt', 'utf8', (err, data1) => {
if (err) return callback(err);
fs.readFile('file2.txt', 'utf8', (err, data2) => {
if (err) return callback(err);
fs.readFile('file3.txt', 'utf8', (err, data3) => {
if (err) return callback(err);
callback(null, data1 + data2 + data3);
});
});
});
}
readFiles((err, result) => {
if (err) console.error(err);
else console.log(result);
});
使用 Promise
JavaScript
const fs = require('fs').promises;
async function readFiles() {
const data1 = await fs.readFile('file1.txt', 'utf8');
const data2 = await fs.readFile('file2.txt', 'utf8');
const data3 = await fs.readFile('file3.txt', 'utf8');
return data1 + data2 + data3;
}
readFiles().then(console.log).catch(console.error);
回调函数注意事项
JavaScript
// ❌ 错误:直接抛出异常会丢失
function badCallback() {
setTimeout(() => {
throw new Error('无法捕获');
}, 1000);
}
// ✅ 正确:通过回调传递错误
function goodCallback(callback) {
setTimeout(() => {
callback(new Error('通过回调传递'));
}, 1000);
}
goodCallback((err) => {
if (err) console.error(err);
});
回调中的异常无法被外部 try-catch 捕获,必须通过回调传递错误。
要点总结
- 回调函数在操作完成后被调用
- Node.js 回调遵循 Error-First 规范(第一个参数为错误)
- 多层嵌套导致回调地狱,代码难以维护
- 使用 Promise 或拆分函数解决回调地狱
- 回调中的异常无法被外部捕获
📝 发现内容有误?点击此处直接编辑