Promise 对象
Promise 是什么
Promise 是为了解决 JavaScript 中的异步编程问题而引入的一种机制。
Promise 解决了什么问题
在 JavaScript 中,许多操作都是异步的,例如网络请求、文件读写、定时器等。在传统的回调函数方式中,处理多个异步操作会导致代码嵌套层级过深,可读性差,维护困难,被称为“回调地狱”(Callback Hell)。
以下是一个简单的例子来说明回调地狱的问题。假设我们需要按顺序执行三个异步操作:获取用户信息、获取用户订单列表、获取订单详情。每个操作都需要通过回调函数来处理结果。
getUserInfo((userInfo) => {
getOrderList(userInfo.userId, (orderList) => {
getOrderDetails(orderList[0].orderId, (orderDetails) => {
// 处理订单详情
});
});
});
getUserInfo((userInfo) => {
getOrderList(userInfo.userId, (orderList) => {
getOrderDetails(orderList[0].orderId, (orderDetails) => {
// 处理订单详情
});
});
});
在这个例子中,每个异步操作都依赖于上一个操作的结果,因此需要将后续操作的代码嵌套在回调函数中。随着操作的增多,嵌套的层级会不断增加,导致代码的缩进增多,可读性变差,而且很容易出现错误。
为了解决这个问题,Promise 提供了一种更优雅、更结构化的方式来处理异步操作。它将异步操作封装成一个 Promise 对象,可以通过链式调用的方式处理异步操作的结果和错误。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败),可以根据异步操作的结果来改变状态。Promise 对象的状态一旦改变,就不会再变化。
使用 Promise,可以将异步操作的处理逻辑从回调函数中提取出来,使代码更加清晰、易读。同时,Promise 还提供了一些方法,如 .then()、.catch() 和 .finally(),用于处理异步操作的结果和错误,使代码更加可控。
Promise 的基本用法
Promise 是一个构造函数,可以通过 new 关键字来创建一个 Promise 对象。Promise 构造函数接收一个函数作为参数,该函数的两个参数分别是 resolve 和 reject,它们都是函数类型。resolve 函数用于将 Promise 对象的状态从 pending(进行中)变为 fulfilled(已成功),reject 函数用于将 Promise 对象的状态从 pending(进行中)变为 rejected(已失败)。
创建 Promise 对象
- 用法
const promise = new Promise((resolve, reject) => {
// 异步操作
// 处理成功,调用 resolve
// 处理失败,调用 reject
});
const promise = new Promise((resolve, reject) => {
// 异步操作
// 处理成功,调用 resolve
// 处理失败,调用 reject
});
- 案例
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
处理 Promise 成功状态的回调函数
- 用法
promise.then((result) => {
// 处理成功状态的逻辑
});
promise.then((result) => {
// 处理成功状态的逻辑
});
- 案例
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
promise.then((data) => {
console.log(data);
});
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
promise.then((data) => {
console.log(data);
});
有的小伙伴,可能不太理解,promise.then() 里面的回调函数的形参参数(data),代表的具体是谁?其实,在正常执行情况下,promise.then() 里面的回调函数可以理解为是 resolve,因为 resolve 、reject 本身就是一个函数。即:promise.then(resolve)
处理 Promise 失败状态的回调函数
- 用法
promise.catch((error) => {
// 处理失败状态的逻辑
});
promise.catch((error) => {
// 处理失败状态的逻辑
});
- 案例
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
promise.catch((error) => {
console.log(error);
});
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
promise.catch((error) => {
console.log(error);
});
处理 Promise 无论成功或失败状态的回调函数
- 用法
promise.finally(() => {
// 处理成功或失败状态的逻辑
});
promise.finally(() => {
// 处理成功或失败状态的逻辑
});
- 案例
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
promise.finally(() => {
console.log("无论成功或失败都会执行");
});
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
let count = Math.random() * 10;
if (count < 5) {
// 当随机数小于5,promise完成了执行
resolve(count);
} else {
reject("错误,count>5");
}
console.log("执行完成");
}, 1000);
});
promise.finally(() => {
console.log("无论成功或失败都会执行");
});
Promise 的链式调用
- 用法
promise
.then((result) => {
// 处理成功状态的逻辑
return anotherPromise; // 返回另一个 Promise 对象
})
.then((result) => {
// 处理另一个 Promise 成功状态的逻辑
})
.catch((error) => {
// 处理任何一个 Promise 失败状态的逻辑
});
promise
.then((result) => {
// 处理成功状态的逻辑
return anotherPromise; // 返回另一个 Promise 对象
})
.then((result) => {
// 处理另一个 Promise 成功状态的逻辑
})
.catch((error) => {
// 处理任何一个 Promise 失败状态的逻辑
});
- 案例
const promise = new Promise((resolve, reject) => {
resolve(1);
})
.then((value) => {
console.log("value1", value);
return value * 10;
})
.then((value) => {
console.log("value2", value);
})
.then((value) => {
console.log("value3", value);
});
const promise = new Promise((resolve, reject) => {
resolve(1);
})
.then((value) => {
console.log("value1", value);
return value * 10;
})
.then((value) => {
console.log("value2", value);
})
.then((value) => {
console.log("value3", value);
});
并行执行多个 Promise, 返回所有 Promise 的结果
- 用法
Promise.all([promise1, promise2, promise3])
.then((results) => {
// 处理所有 Promise 成功状态的逻辑,results 是一个包含所有结果的数组
})
.catch((error) => {
// 处理任何一个 Promise 失败状态的逻辑
});
Promise.all([promise1, promise2, promise3])
.then((results) => {
// 处理所有 Promise 成功状态的逻辑,results 是一个包含所有结果的数组
})
.catch((error) => {
// 处理任何一个 Promise 失败状态的逻辑
});
- 案例
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 1");
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 2");
}, 1500);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 3");
}, 1000);
});
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log(results); // ['Result 1', 'Result 2', 'Result 3']
// 处理所有 Promise 成功状态的逻辑
})
.catch((error) => {
console.error(error); // 如果任何一个 Promise 失败,会在这里处理错误
// 处理任何一个 Promise 失败状态的逻辑
});
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 1");
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 2");
}, 1500);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 3");
}, 1000);
});
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log(results); // ['Result 1', 'Result 2', 'Result 3']
// 处理所有 Promise 成功状态的逻辑
})
.catch((error) => {
console.error(error); // 如果任何一个 Promise 失败,会在这里处理错误
// 处理任何一个 Promise 失败状态的逻辑
});
在这个例子中,我们创建了三个 Promise 对象,每个 Promise 都会在不同的时间间隔后返回一个结果。使用 Promise.all 方法,我们将这三个 Promise 对象传递给它,并在所有 Promise 都成功完成后获取它们的结果。在 .then 方法中,我们可以处理所有 Promise 成功状态的逻辑,并在控制台打印结果数组。如果任何一个 Promise 失败,会立即触发 .catch 方法,并在控制台打印错误信息。
并行执行多个 Promise,返回最先执行完的 Promise 的结果
- 用法
Promise.race([promise1, promise2, promise3])
.then((result) => {
// 处理第一个 Promise 成功状态的逻辑
})
.catch((error) => {
// 处理第一个 Promise 失败状态的逻辑
});
Promise.race([promise1, promise2, promise3])
.then((result) => {
// 处理第一个 Promise 成功状态的逻辑
})
.catch((error) => {
// 处理第一个 Promise 失败状态的逻辑
});
- 案例
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 1");
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 2");
}, 1500);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 3");
}, 1000);
});
Promise.race([promise1, promise2, promise3])
.then((result) => {
console.log(result); // 'Result 3'
// 处理第一个 Promise 成功状态的逻辑
})
.catch((error) => {
console.error(error); // 如果第一个 Promise 失败,会在这里处理错误
// 处理第一个 Promise 失败状态的逻辑
});
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 1");
}, 2000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 2");
}, 1500);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Result 3");
}, 1000);
});
Promise.race([promise1, promise2, promise3])
.then((result) => {
console.log(result); // 'Result 3'
// 处理第一个 Promise 成功状态的逻辑
})
.catch((error) => {
console.error(error); // 如果第一个 Promise 失败,会在这里处理错误
// 处理第一个 Promise 失败状态的逻辑
});
Promise.resolve(value)
在实际开发过程中,有时需要将现有对象转为 Promise 对象,Promise.resolve 方法就起到这个作用
new Promise((resolve) => resolve("Hello World"));
// 等价于
Promise.resolve("Hello World");
new Promise((resolve) => resolve("Hello World"));
// 等价于
Promise.resolve("Hello World");
静态方法 Promise.resolve(value) 可以认为是 new Promise() 方法的快捷方式。
创建 Promise 异步函数
const getShopDetailById = (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟后端请求
let count = Math.random() * 10;
if (id && count < 5) {
// 当随机数小于5,假设后端接口正常返回数据
resolve({ code: 0, msg: "ok" });
} else {
reject("接口异常");
}
}, 1000);
});
};
// 假如商品的主键id为:1
getShopDetailById("1").then((data) => {
console.log(data);
});
const getShopDetailById = (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟后端请求
let count = Math.random() * 10;
if (id && count < 5) {
// 当随机数小于5,假设后端接口正常返回数据
resolve({ code: 0, msg: "ok" });
} else {
reject("接口异常");
}
}, 1000);
});
};
// 假如商品的主键id为:1
getShopDetailById("1").then((data) => {
console.log(data);
});
创建异步函数还有更好的方案,那就是 async/await。继续看下一篇吧。