1. 语法糖的概念
定义
语法糖
(Syntactic Sugar)是指在编程语言中添加的语法,它不会增加语言的表达能力,但使代码更易读、更简洁
。
示例
// 普通函数写法
function add(a, b) {
return a + b;
}
// 箭头函数语法糖
const add = (a, b) => a + b;
2. 回调函数与回调地狱
回调函数概念
回调函数是作为参数传递给另一个函数,并在特定事件发生后执行的函数。
回调地狱示例
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
getMoreData(c, function(d) {
// 嵌套层级过深,代码难以维护
console.log(d);
});
});
});
});
回调地狱问题
- 代码可读性差
- 错误处理困难
- 调试复杂
- 代码维护成本高
3. Promise 基础
概念
Promise 是异步编程
的一种解决方案,代表一个异步操作的最终完成(或失败)及其结果值。
状态
Promise 有三种状态:
Pending
: 初始状态,既不是成功也不是失败Fulfilled
: 操作成功完成Rejected
: 操作失败
基本用法
const promise = new Promise((resolve, reject) => {
// 异步操作
if (/* 操作成功 */) {
resolve(value); // 成功
} else {
reject(error); // 失败
}
});
promise
.then(value => {
// 处理成功
})
.catch(error => {
// 处理错误
})
.finally(() => {
// 无论成功失败都会执行
});
4. Promise 底层原理
Promise 实现原理
Promise 本质上是一个状态机,通过发布-订阅
模式来实现异步操作的管理。
简化版 Promise 实现
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
// 简化实现
if (this.state === 'fulfilled') {
onFulfilled(this.value);
}
if (this.state === 'rejected') {
onRejected(this.reason);
}
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
onFulfilled(this.value);
});
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
});
}
}
}
5. async/await 语法
概念
async/await
是 ES2017 引入的语法糖,用于更简洁地处理 Promise。
关键点
async
函数总是返回一个 Promiseawait
只能在async
函数内部使用await
使 JavaScript 引擎等待 Promise 解决,然后继续执行
代码对比
// 使用 Promise 链
function getData() {
return fetchData()
.then(data => {
return processData(data);
})
.then(result => {
return formatData(result);
})
.catch(err => {
console.error(err);
});
}
// 使用 async/await
async function getData() {
try {
const data = await fetchData();
const result = await processData(data);
return await formatData(result);
} catch (err) {
console.error(err);
}
}
6. async/await 底层原理
生成器函数
async/await 底层是基于生成器(Generator)和 Promise 实现的。
function* generatorFunction() {
const data = yield fetchData();
const result = yield processData(data);
return formatData(result);
}
转换过程
JavaScript 引擎会将 async/await 转换为基于 Promise 的状态机和自动执行器。
// 简化版自动执行器
function run(generatorFunction) {
const generator = generatorFunction();
function handle(result) {
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(
res => handle(generator.next(res)),
err => handle(generator.throw(err))
);
}
return handle(generator.next());
}
7. Promise 常用方法
Promise.all()
并行执行多个 Promise,全部成功才成功,有一个失败则整体失败。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // [1, 2, 3]
})
.catch(error => {
console.error(error);
});
Promise.race()
返回最先解决或拒绝的 Promise 结果。
const promise1 = new Promise(resolve => setTimeout(() => resolve('一'), 500));
const promise2 = new Promise(resolve => setTimeout(() => resolve('二'), 100));
Promise.race([promise1, promise2])
.then(value => {
console.log(value); // '二' (更快)
});
Promise.allSettled()
等待所有 Promise 完成(无论成功或失败)。
const promises = [
Promise.resolve(1),
Promise.reject('错误'),
Promise.resolve(3)
];
Promise.allSettled(promises)
.then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: '错误' },
// { status: 'fulfilled', value: 3 }
// ]
});
Promise.any()
返回第一个成功的 Promise,全部失败才失败。
const promises = [
Promise.reject('错误1'),
Promise.resolve('成功'),
Promise.reject('错误2')
];
Promise.any(promises)
.then(value => {
console.log(value); // '成功'
})
.catch(errors => {
console.error(errors); // 所有 Promise 都拒绝时执行
});
8. 实际应用场景
并行数据加载
async function loadDashboard() {
try {
// 并行加载数据
const [userData, statsData, notificationsData] = await Promise.all([
fetchUserData(),
fetchStats(),
fetchNotifications()
]);
renderDashboard(userData, statsData, notificationsData);
} catch (error) {
showErrorMessage(error);
}
}
超时处理
function fetchWithTimeout(url, ms) {
const fetchPromise = fetch(url);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('请求超时')), ms);
});
return Promise.race([fetchPromise, timeoutPromise]);
}
// 使用
fetchWithTimeout('/api/data', 5000)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
顺序处理与并行处理对比
// 顺序执行 - 总耗时是所有任务耗时之和
async function sequential() {
console.time('sequential');
const result1 = await task1();
const result2 = await task2(result1);
const result3 = await task3(result2);
console.timeEnd('sequential');
return result3;
}
// 并行执行 - 总耗时约等于最长任务的耗时
async function parallel() {
console.time('parallel');
const [result1, result2, result3] = await Promise.all([
task1(), task2(), task3()
]);
console.timeEnd('parallel');
return [result1, result2, result3];
}
9. 异步编程最佳实践
错误处理
async function robustFunction() {
try {
const data = await riskyOperation();
return processData(data);
} catch (error) {
// 处理特定错误
if (error instanceof NetworkError) {
return fallbackNetworkOperation();
}
// 记录并重新抛出其他错误
logger.error(error);
throw error;
} finally {
// 清理资源
cleanup();
}
}
避免回调地狱的方法
- 使用 Promise 链
- 采用 async/await
- 提取函数,减少嵌套
- 使用 Promise 组合方法
// 反模式: 回调地狱
function processData(callback) {
fetchData(function(data) {
processStep1(data, function(result1) {
processStep2(result1, function(result2) {
processStep3(result2, function(result3) {
callback(result3);
});
});
});
});
}
// 最佳实践: async/await
async function processData() {
try {
const data = await fetchData();
const result1 = await processStep1(data);
const result2 = await processStep2(result1);
return await processStep3(result2);
} catch (error) {
console.error('处理数据时出错:', error);
throw error;
}
}
10. 总结
概念图谱
语法糖 → 简化代码表达
↓
回调函数 → 回调地狱
↓
Promise → 优雅处理异步
↓
async/await → Promise的语法糖
↓
Promise.all/race/allSettled/any → 组合异步操作
↓
现代异步编程范式
各概念核心关系
- 回调函数是最早的异步处理方式,但易导致回调地狱
- Promise通过链式调用解决回调地狱问题
- async/await是基于Promise的语法糖,使异步代码看起来像同步代码
- Promise组合方法用于处理多个异步操作的协调问题