摘要: 作为一个编程新手,面对 JavaScript 中的异步操作,你是否曾被层层嵌套的回调函数搞得晕头转向?Promise 是 ES6 中引入的异步编程解决方案,它不仅解决了“回调地狱”问题,还让代码逻辑更加清晰。
一、为什么要学 Promise?告别“回调地狱”
在 JavaScript 的世界里,异步操作(如定时器、网络请求、文件读取)是家常便饭。在 ES6 之前,我们主要依靠回调函数(Callback) 来处理异步逻辑。
假设我们需要依次执行三个异步任务(A -> B -> C),传统的写法可能是这样的:
// 伪代码:回调地狱
doAsyncTaskA(function(resultA) {
doAsyncTaskB(resultA, function(resultB) {
doAsyncTaskC(resultB, function(resultC) {
console.log('所有任务完成:', resultC);
});
});
});
这种层层嵌套的写法被称为 “回调地狱”(Callback Hell) 。随着业务逻辑变复杂,代码会变得难以阅读和维护。
Promise 的出现就是为了解决这个问题。
什么是 Promise?
简单来说,Promise 是一个对象,代表一个现在、将来完成或可能永远不完成的异步操作。它就像一张“契约”:
-
状态不可逆:Promise 有三种状态:
pending(等待中)fulfilled(成功/已兑现)rejected(失败/已拒绝)- 状态一旦从
pending变为fulfilled或rejected,就永远凝固,不会再改变。
-
立即执行:创建 Promise 实例时,传入的执行函数(Executor)会立即执行。
二、Promise 的核心用法(ES6 标准)
Promise 是一个构造函数,接收一个函数作为参数,该函数包含两个参数:resolve 和 reject。
1. 基础结构
const promise = new Promise((resolve, reject) => {
// 异步操作代码
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
resolve('成功!数据是:' + random); // 调用 resolve,状态变为 fulfilled
} else {
reject('失败!数字太小'); // 调用 reject,状态变为 rejected
}
}, 1000);
});
2. then 方法:链式调用的灵魂
then 方法用于指定状态改变后的回调函数。它有两个参数,分别对应成功和失败的回调。
- 链式调用:
then方法返回的是一个新的 Promise 对象,这使得我们可以进行链式调用,彻底摆脱嵌套。
promise
.then(
(data) => { console.log('成功:', data); return data; }, // 成功回调
(err) => { console.log('失败:', err); } // 失败回调(通常建议用 catch 代替)
)
.then((data) => {
// 这里的 data 是上一个 then 返回的结果
console.log('上一步的结果传递过来了:', data);
});
3. catch 方法:错误捕获
catch 专门用于处理错误,相当于 then(null, rejection)。它还有一个重要功能:捕获前面任何 then 中抛出的异常(类似于 try...catch)。
promise
.then(data => {
console.log(someUndefinedVar); // 这里会报错
})
.catch(err => {
console.log('捕获到错误了:', err); // 即使代码出错,也能被捕获,不会卡死
});
4. 静态方法:批量处理异步
Promise 还提供了一些静态方法来处理多个异步操作:
-
Promise.all([...]):谁跑得慢,以谁为准。- 接收一个 Promise 数组。
- 全成功才成功:所有任务都成功完成,结果按顺序组成数组。
- 一失败即失败:只要有一个失败,就立即进入 reject。
function createTask(name, delay, success = true) { return new Promise((resolve, reject) => { setTimeout(() => { if (success) { resolve(`✅ ${name} 完成,耗时 ${delay}ms`); } else { reject(`❌ ${name} 失败,耗时 ${delay}ms`); } }, delay); }); } -
Promise.race([...]):谁跑得快,以谁为准。- 接收一个 Promise 数组。
- 一决生死:哪个 Promise 最先改变状态(无论是成功还是失败),
race的状态就跟着它走。 - 场景:设置请求超时。
function timeout(ms) { return new Promise((_, reject) => { setTimeout(() => { reject(`⏰ 请求超时,超过 ${ms}ms`); }, ms); }); }