🎯 第 8 课:回调函数(Callback)与非阻塞 I/O

0 阅读2分钟

📌 核心知识点
Node.js 使用“回调函数”来处理异步操作,实现非阻塞 I/O,从而高效应对大量并发请求。


🤔 为什么需要“非阻塞”?

想象一下你在餐厅点餐:

  • ❌ 阻塞方式(传统语言如 PHP):
    你点完菜后,服务员站在你桌边等厨房做好再走 —— 这期间他不能服务其他人。
  • ✅ 非阻塞方式(Node.js):
    你点完菜,服务员记下订单就去服务下一位客人;菜好了厨房通知他,他再把菜端给你。

👉 Node.js 就是这个“聪明的服务员”,用 事件 + 回调 实现高效并发。


🔁 什么是回调函数?

简单说: “等我做完这件事,就去执行你给我的函数”

示例:setTimeout

console.log("第一步:开始");

setTimeout(() => {
  console.log("第三步:2秒后执行");
}, 2000);

console.log("第二步:不会等上面");

输出顺序:

第一步:开始
第二步:不会等上面
(等待2秒)
第三步:2秒后执行

✅ 虽然 setTimeout 在中间定义,但它的回调函数最后才执行,而且 不会阻塞后面的代码


💡 回调在 Node.js 中的真实用途

比如读取一个大文件:

❌ 同步读取(会卡住程序)

const fs = require('fs');

console.log('开始读取文件...');
const data = fs.readFileSync('big-file.txt', 'utf8'); // 卡在这里直到读完
console.log('文件读取完成!');
console.log('程序继续运行...');

⚠️ 如果文件很大,这期间整个程序都“冻结”了,无法响应其他请求。


✅ 异步读取(推荐!使用回调)

const fs = require('fs');

console.log('开始读取文件...');

fs.readFile('big-file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('读取失败:', err);
    return;
  }
  console.log('文件读取完成!');
  console.log('内容长度:', data.length);
});

console.log('我不等你,我先走了!');

输出顺序:

开始读取文件...
我不等你,我先走了!
(稍后...)
文件读取完成!
内容长度: 102400

🎉 成功做到了“不等待”!这就是 非阻塞 I/O


📌 回调函数的标准格式

在 Node.js 中,大多数异步方法的回调函数长这样:

function(err, result) {
  if (err) {
    // 处理错误
  } else {
    // 使用 result
  }
}

👉 这叫 Error-First Callback(错误优先回调),是 Node.js 的约定。


✅ 小结一句话:

回调函数是 Node.js 实现“异步、非阻塞”的核心方式:告诉系统“事情做完后调用我这个函数”,而不是傻等结果。


🧠 类比记忆:

生活场景对应编程概念
点外卖后继续工作,收到通知再去拿回调函数
给快递员留纸条:“送到后打电话给我”注册回调
快递没送到是因为地址错 → 收到电话说送不了错误优先回调中的 err

📬 下一课预告:
第 9 课:回调地狱(Callback Hell)与解决方案 —— 如何避免层层嵌套?

我们将看到当多个异步操作串联时会出现什么问题,以及如何解决它。