异步编程核心概念
JavaScript 是单线程语言,异步编程用于处理耗时操作(网络请求、定时器、文件读取)而不阻塞主线程。
回调函数
基本概念
将函数作为参数传递给异步操作,在操作完成后调用:
JavaScript
function fetchData(callback) {
setTimeout(() => {
const data = { id: 1, name: 'Tom' };
callback(data);
}, 1000);
}
fetchData((result) => {
console.log(result); // { id: 1, name: 'Tom' }
});
回调地狱
多层嵌套导致代码难以维护:
JavaScript
getUser(id, (user) => {
getOrders(user.id, (orders) => {
getDetails(orders[0].id, (details) => {
console.log(details);
});
});
});
错误优先回调
Node.js 风格的约定,第一个参数为错误对象:
JavaScript
function readFile(path, callback) {
if (!path) {
callback(new Error('path required'), null);
return;
}
callback(null, 'file content');
}
readFile('/path', (err, data) => {
if (err) {
console.error(err.message);
return;
}
console.log(data);
});
Promise
创建 Promise
JavaScript
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('数据获取成功');
} else {
reject('数据获取失败');
}
}, 1000);
});
then / catch / finally
JavaScript
promise
.then((result) => {
console.log(result); // '数据获取成功'
return result + '!';
})
.then((enhanced) => {
console.log(enhanced); // '数据获取成功!'
})
.catch((error) => {
console.error(error);
})
.finally(() => {
console.log('操作完成');
});
链式调用解决回调地狱
JavaScript
getUser(id)
.then((user) => getOrders(user.id))
.then((orders) => getDetails(orders[0].id))
.then((details) => console.log(details))
.catch((err) => console.error(err));
Promise 静态方法
JavaScript
// 立即 resolve
Promise.resolve('done').then(console.log);
// 立即 reject
Promise.reject('fail').catch(console.error);
// 等待所有完成
Promise.all([p1, p2, p3]).then(results => {
console.log(results); // [r1, r2, r3]
});
// 返回最快完成的
Promise.race([p1, p2, p3]).then(result => {
console.log(result);
});
async / await
基本语法
JavaScript
async function fetchUser(id) {
const response = await fetch(`/api/user/${id}`);
const user = await response.json();
return user;
}
fetchUser(1).then(user => console.log(user));
错误处理
JavaScript
async function loadData() {
try {
const user = await getUser(1);
const orders = await getOrders(user.id);
return orders;
} catch (error) {
console.error('加载失败:', error.message);
return [];
}
}
对比三种方式
| 方式 | 可读性 | 错误处理 | 适用场景 |
|---|---|---|---|
| 回调 | 差 | 分散 | 简单事件 |
| Promise | 中 | 链式捕获 | 链式异步操作 |
| async/await | 好 | try/catch | 顺序异步逻辑 |
async 函数始终返回 Promise,await 只能在 async 函数内使用。
要点总结
- 回调是最基础的异步模式,但容易产生回调地狱
- Promise 通过链式调用扁平化异步代码
- async/await 让异步代码写起来像同步代码
- 优先使用 async/await,配合 try/catch 处理错误
Promise.all用于并行执行多个异步任务