JavaScript异步编程
📌 1. JavaScript 为什么需要异步?
JavaScript 是 单线程(Single-threaded)语言,它的执行方式是逐行执行,但有时候代码的执行可能会遇到等待:
- 你去点咖啡(等待制作)。
- 你从服务器请求数据(等待网络)。
- 你读取一个文件(等待磁盘)。
如果JavaScript只能同步执行,遇到等待时,整个程序都会卡住,无法继续执行。为了解决这个问题,JavaScript引入了异步编程。
📌 2. 回调函数(Callback)—— 传统异步
最原始的异步方案是回调函数(callback),即当任务完成时,调用一个函数来处理结果。
💡 例子:回调函数点咖啡
1 | function orderCoffee(callback) { |
📌 运行结果
1 | 开始制作咖啡... |
🔹 回调的缺点
- 回调地狱(Callback Hell):
- 如果有多个步骤(如:点咖啡 → 加糖 → 加奶),代码会变得嵌套很多层,难以维护。
1 | orderCoffee(coffee => { |
- 可读性差,难以调试。
📌 3. 事件循环(Event Loop)—— JavaScript 异步的核心
JavaScript 的 异步任务(如 setTimeout()、Promise、fetch)不是立即执行的,而是放入任务队列,等主线程(同步任务)完成后再执行。这就是事件循环(Event Loop)的工作方式。
💡 事件循环的运作
- JavaScript代码会先执行同步任务(如变量声明、函数调用)。
- 遇到异步任务(如 setTimeout()),它会交给浏览器(WebAPI)执行,完成后将回调函数放入任务队列。
- 当主线程空闲时,事件循环(Event Loop)会把任务队列里的任务放入主线程执行。
💡 例子:事件循环
1 | console.log("1. 我先来杯咖啡"); // 同步任务 |
📌 执行顺序
1 | 1. 我先来杯咖啡 |
📌 4. Promise—— 解决回调地狱
Promise 是 异步任务的容器,它有三种状态:
- pending(等待中)
- fulfilled(已完成)
- rejected(已拒绝)
💡 例子:用 Promise 处理点咖啡
1 | function orderCoffee() { |
📌 执行顺序
1 | 开始制作咖啡... |
Promise 的优势:
- 链式调用,比回调函数更清晰。
- 错误处理更优雅,可以用 .catch()。
📌 5. async/await—— 最清晰的异步写法
async/await是Promise的语法糖,让代码更像同步代码。
💡 例子:async/await 版的点咖啡
1 | function orderCoffee() { |
📌 执行顺序
1 | 我点了一杯咖啡... |
为什么async/await更好?
- 代码更直观,没有 .then() 链式调用。
- 结构更清晰,像同步代码一样易读。
📌 6. Promise.all() 和 Promise.race()
🔹 Promise.all() —— 并行执行
如果你同时点 咖啡、蛋糕、面包,可以用 Promise.all() 并行执行:
1 | const coffee = new Promise(resolve => setTimeout(() => resolve("☕ 咖啡"), 2000)); |
📌 输出
1 | ✅ 早餐准备好啦: ["☕ 咖啡", "🍰 蛋糕", "🥪 面包"] |
🔹 Promise.race() —— 谁先完成返回谁
1 | Promise.race([coffee, cake, bread]) |
📌 输出
1 | ✅ 最快的食物是: 🥪 面包 |
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment
