异步深入
event loop、callbacks、promises、fetch、XHR。
35 分钟
异步深入
javascript-core 介绍 Promise 与 async/await;本课深入 事件循环、微任务/宏任务、回调地狱 与 fetch/XHR。Node 的 process.nextTick 与浏览器差异见 nodejs-essentials。
学习目标
- 画出 call stack、Web APIs、task queue 的关系
- 解释
setTimeout(0)与Promise.then的执行顺序 - 用 fetch 替代 XHR,并处理错误与超时
事件循环模型
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Call Stack │ ←→ │ Web APIs │ → │ Callback Queue │
│ (同步代码) │ │ setTimeout等 │ │ (宏任务) │
└─────────────┘ └──────────────┘ └─────────────────┘
↓
┌─────────────────┐
│ Microtask Queue │
│ Promise.then 等 │
└─────────────────┘
每轮循环:执行一个宏任务 → 清空所有微任务 → 可能渲染 → 下一个宏任务。
经典输出顺序
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
queueMicrotask(() => console.log('D'));
console.log('E');
// A → E → C → D → B
async/await 中 await 之后的代码相当于微任务。
回调与 Promise 演进
// 回调风格(难维护)
getUser(id, (err, user) => {
if (err) return handle(err);
getOrders(user.id, (err2, orders) => {
if (err2) return handle(err2);
render(orders);
});
});
// Promise 链
getUser(id)
.then((user) => getOrders(user.id))
.then(render)
.catch(handle);
// async/await
async function load() {
try {
const user = await getUser(id);
const orders = await getOrders(user.id);
render(orders);
} catch (e) {
handle(e);
}
}
fetch 与错误处理
async function fetchTrack(slug) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch(`/api/tracks/${slug}`, {
signal: controller.signal,
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
return await res.json();
} finally {
clearTimeout(timeout);
}
}