Promise
一、Promise 的核心概念与背景
定义:Promise 是一种处理异步操作的对象,代表一个异步操作的最终完成(或失败)及其结果值。
诞生背景:
- 回调地狱(Callback Hell):多层嵌套的回调函数导致代码可读性差、维护困难。
- 异常处理混乱:异步操作的错误无法通过传统
try-catch
捕获。
Promise 的三大状态:
- pending:初始状态,既不是成功也不是失败。
- fulfilled:操作成功完成。
- rejected:操作失败。
状态一旦改变(从 pending 到 fulfilled 或 rejected),就会被冻结,不可再变。
二、Promise 的基本用法
1. 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作(如网络请求、定时器)
setTimeout(() => {
const success = true;
if (success) {
resolve('操作成功'); // 传递成功结果
} else {
reject(new Error('操作失败')); // 传递失败原因
}
}, 1000);
});
2. 消费 Promise
promise
.then((value) => {
console.log(value); // 输出:操作成功
})
.catch((error) => {
console.error(error); // 捕获错误
})
.finally(() => {
console.log('无论成功失败都会执行');
});
3. Promise 链式调用
fetchData()
.then((data) => processData(data)) // 返回新 Promise
.then((processedData) => saveData(processedData))
.catch((error) => handleError(error)); // 统一错误处理
三、Promise 的高级特性
1. Promise 静态方法
-
Promise.all(iterable):
并行执行多个 Promise,全部成功时返回结果数组,任一失败则立即失败。Promise.all([promise1, promise2])
.then(([result1, result2]) => { /* 处理结果 */ })
.catch((error) => { /* 处理任一错误 */ }); -
Promise.race(iterable):
多个 Promise 竞争,第一个完成(无论成功或失败)的结果作为最终结果。// 实现请求超时控制
Promise.race([fetchData(), timeout(5000)])
.then((data) => { /* 处理数据 */ })
.catch((error) => { /* 处理超时或请求错误 */ }); -
Promise.allSettled(iterable):
等待所有 Promise 完成(无论成功或失败),返回包含每个结果状态的数组。Promise.allSettled([promise1, promise2])
.then((results) => {
results.forEach((result) => {
if (result.status === 'fulfilled') {
console.log(result.value);
} else {
console.error(result.reason);
}
});
});
2. 错误处理最佳实践
-
全局错误捕获:
window.addEventListener('unhandledrejection', (event) => {
console.error('未捕获的 Promise 错误:', event.reason);
event.preventDefault(); // 阻止默认行为(如控制台警告)
}); -
链式捕获 vs 单独捕获:
// 链式捕获:任何环节出错都会被最终 catch 捕获
promise.then(a).then(b).catch(error => { /* 处理所有错误 */ });
// 单独捕获:仅捕获当前 Promise 的错误
promise.then(a).catch(errA).then(b).catch(errB);
四、Promise 与 async/await 的结合
async/await 是 Promise 的语法糖,使异步代码更像同步代码:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('请求失败:', error);
throw error; // 继续向上抛出错误
}
}
// 调用异步函数
fetchData()
.then((data) => processData(data))
.catch((error) => handleError(error));
五、Promise 的性能优化
-
避免不必要的串行执行:
// 错误:串行执行(等待第一个完成再执行第二个)
const result1 = await fetchData1();
const result2 = await fetchData2();
// 正确:并行执行(提高效率)
const [result1, result2] = await Promise.all([fetchData1(), fetchData2()]); -
限制并发数量:
// 实现并发控制(如同时最多 3 个请求)
function limitConcurrency(tasks, concurrency) {
let running = 0;
const results = [];
return new Promise((resolve, reject) => {
const runNext = async () => {
if (tasks.length === 0) {
if (running === 0) resolve(results);
return;
}
running++;
const task = tasks.shift();
try {
const result = await task();
results.push(result);
} catch (error) {
reject(error);
} finally {
running--;
runNext();
}
};
// 启动初始并发任务
for (let i = 0; i < Math.min(concurrency, tasks.length); i++) {
runNext();
}
});
}
六、Promise 的常见误区与陷阱
-
忘记返回 Promise:
// 错误:未返回 Promise,导致链式调用中断
.then(() => {
fetchData(); // 未返回
})
// 正确
.then(() => fetchData()) -
空 catch 块掩盖错误:
// 错误:捕获错误后不处理
.catch(() => {})
// 正确:至少记录错误
.catch((error) => {
console.error('捕获到错误:', error);
throw error; // 继续传播错误
}) -
同步代码中的 Promise 未被捕获:
// 错误:同步代码中直接抛出的错误无法被 Promise 捕获
const promise = new Promise((resolve, reject) => {
throw new Error('同步错误'); // 立即抛出,未被 reject 包装
});
// 正确:使用 try-catch 包裹同步代码
const promise = new Promise((resolve, reject) => {
try {
// 可能抛出错误的同步代码
} catch (error) {
reject(error);
}
});
七、总结:Promise 的核心价值
- 解决回调地狱:通过链式调用替代嵌套回调。
- 统一的错误处理:使用
catch
捕获整条链上的错误。 - 并行与竞争控制:通过
all
、race
等方法高效处理多个异步操作。 - 与 async/await 无缝集成:提供更优雅的异步代码写法。
Promise 是现代 JavaScript 异步编程的基础,掌握其原理和最佳实践是编写高性能、可维护代码的关键。