JavaScript 异步编程
大约 2 分钟
JavaScript 异步编程
JavaScript 是单线程语言,异步编程是处理耗时操作(如网络请求、定时任务)的关键。
回调函数 (Callbacks)
最基础的异步处理方式,但容易导致“回调地狱”。
function getData(callback) {
setTimeout(() => {
callback("Data loaded");
}, 1000);
}
getData((data) => {
console.log(data);
// 嵌套回调...
});
Promise
Promise 对象代表一个异步操作的最终完成(或失败)及其结果值。解决了回调地狱的问题。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve("Operation success");
} else {
reject("Operation failed");
}
}, 1000);
});
myPromise
.then(result => {
console.log(result);
return "Next step";
})
.then(next => {
console.log(next);
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log("Done");
});
Promise.all
并行执行多个 Promise,全部成功才成功,有一个失败则失败。
const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
Promise.all([p1, p2]).then(values => {
console.log(values); // [1, 2]
});
Promise.race
返回第一个完成(无论成功或失败)的 Promise 的结果。
const p1 = new Promise(resolve => setTimeout(() => resolve("Fast"), 100));
const p2 = new Promise(resolve => setTimeout(() => resolve("Slow"), 500));
Promise.race([p1, p2]).then(value => {
console.log(value); // "Fast"
});
Async/Await
ES2017 引入的语法糖,基于 Promise,使异步代码看起来像同步代码,可读性极高。
async函数返回一个 Promise。await只能在async函数内部使用,等待 Promise 解决。
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function fetchUser() {
try {
console.log("Start fetching...");
await delay(1000); // 模拟网络延迟
const user = { id: 1, name: "Async User" };
console.log("User fetched:", user);
return user;
} catch (error) {
console.error("Error:", error);
}
}
// 错误处理模式
async function errorHandling() {
// 方式 1: try-catch
try {
await Promise.reject("Oops");
} catch (e) {
console.log("Caught:", e);
}
// 方式 2: catch() 链式调用
await Promise.reject("Oops 2").catch(e => console.log("Caught 2:", e));
}
fetchUser();
串行 vs 并行
async function serial() {
await delay(1000);
await delay(1000);
console.log("2 seconds passed");
}
async function parallel() {
const p1 = delay(1000);
const p2 = delay(1000);
await p1;
await p2;
console.log("1 second passed (approx)");
}
Event Loop (事件循环)
JavaScript 运行时模型基于“事件循环”。
- 调用栈 (Call Stack): 执行同步代码。
- 任务队列 (Task Queue / Callback Queue): 存放宏任务 (MacroTask),如
setTimeout,setInterval, I/O。 - 微任务队列 (Microtask Queue): 存放微任务 (MicroTask),如
Promise.then,process.nextTick(Node.js)。
执行顺序:
- 执行栈中的同步代码。
- 清空微任务队列中的所有任务。
- 从宏任务队列中取出一个任务执行。
- 重复步骤 2-3。
console.log('1'); // 同步
setTimeout(() => {
console.log('2'); // 宏任务
}, 0);
Promise.resolve().then(() => {
console.log('3'); // 微任务
});
console.log('4'); // 同步
// 输出顺序: 1 -> 4 -> 3 -> 2
Loading...
