Promise学习
理论知识
在前端开发中,Promise
是 JavaScript 中用于处理异步操作的一种方式。它提供了一种更直观和简洁的方式来处理异步任务,避免了传统回调函数中“回调地狱”的问题。以下是关于 Promise
的详细解释和代码示例。
什么是 Promise?
Promise 确实可以被看作是异步操作的返回结果
Promise
是一个代表异步操作最终完成或失败的对象。它可以用来处理异步操作的结果(成功或失败)并执行相应的操作。
它会在异步操作完成后,通过 resolve 或 reject 返回结果。这个结果可以是操作成功的值,也可以是操作失败的原因。通过使用 then、catch 和 finally 等方法,你可以定义当异步操作完成后该执行的操作。
const promise = new Promise((resolve, reject) => {
// 一些异步操作,比如数据请求
const success = true;
if (success) {
resolve("操作成功!");
} else {
reject("操作失败!");
}
});
在这个例子中,Promise
构造函数接受一个执行器函数(executor
),该函数带有两个参数:resolve
和 reject
。resolve
用于异步操作成功时返回结果,reject
用于异步操作失败时返回错误。
Promise 的状态
一个 Promise
对象有三种状态:
- Pending(待定): 初始状态,既没有被解决也没有被拒绝。
- Fulfilled(已解决): 操作成功完成,Promise 被解决,
resolve
被调用。 - Rejected(已拒绝): 操作失败,Promise 被拒绝,
reject
被调用。
状态一旦从 Pending
变为 Fulfilled
或 Rejected
,就不能再更改。
resolve 和 reject
resolve 用于异步操作成功时返回结果,reject 用于异步操作失败时返回错误。也就在resolve 里面传递的参数就是异步操作成功后返回的结果
-
resolve
:当异步操作成功时,resolve
函数会被调用,并且可以接收一个参数,这个参数就是异步操作成功后的结果。调用resolve
会将Promise
的状态从“进行中(pending)”变为“已解决(fulfilled)”,并将resolve
传入的值作为结果返回给.then()
方法。 -
reject
:当异步操作失败时,reject
函数会被调用,并且可以接收一个参数,这个参数通常是一个错误信息或对象。调用reject
会将Promise
的状态从“进行中(pending)”变为“已拒绝(rejected)”,并将reject
传入的值作为错误信息返回给.catch()
方法。
示例
const myPromise = new Promise((resolve, reject) => {
const success = true; // 假设这个变量决定操作是否成功
if (success) {
resolve('操作成功!'); // 成功时调用 resolve,并传入结果
} else {
reject('操作失败!'); // 失败时调用 reject,并传入错误信息
}
});
myPromise
.then(result => {
console.log(result); // 输出 "操作成功!"
})
.catch(error => {
console.error(error); // 如果失败,会输出错误信息
});
在这个例子中:
- 如果
success
为true
,resolve('操作成功!')
会被调用,Promise
状态变为“已解决”,并将'操作成功!'
作为结果传递给.then()
。 - 如果
success
为false
,reject('操作失败!')
会被调用,Promise
状态变为“已拒绝”,并将'操作失败!'
作为错误信息传递给.catch()
。
因此,resolve
和 reject
就是用来分别处理异步操作的成功和失败结果的。
Promise 的方法
Promise
提供了一些方法来处理异步操作的结果和错误:
-
then()
- 用于处理
Promise
成功的情况。 - 它接受两个回调函数,第一个用于处理
resolve
的结果,第二个用于处理reject
的错误(可选)。
promise.then(result => { console.log(result); // 操作成功! }, error => { console.error(error); // 不会执行,因为操作成功了 });
- 用于处理
then 方法可以链式调用,这意味着每个 then 都可以返回一个新的 Promise 或数据,供下一个 then 处理。catch 方法用于捕获任何可能的错误
-
catch()
- 用于处理
Promise
失败的情况,相当于then
的第二个参数。
promise.catch(error => { console.error(error); // 操作失败! });
- 用于处理
-
finally()
- 无论
Promise
成功还是失败,都会执行finally
中的回调函数。
promise.finally(() => { console.log("操作完成,无论成功与否"); // 一定会执行 });
- 无论
-
Promise.all()
- 接受一个
Promise
对象的数组,等待所有Promise
都解决后或有一个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] });
- 接受一个
-
Promise.race()
- 接受一个
Promise
对象的数组,一旦有一个Promise
被解决或拒绝,立即继续。
const promise1 = new Promise(resolve => setTimeout(resolve, 500, "One")); const promise2 = new Promise(resolve => setTimeout(resolve, 100, "Two")); Promise.race([promise1, promise2]).then(value => { console.log(value); // Two });
- 接受一个
-
Promise.allSettled()
- 接受一个
Promise
对象的数组,等待所有Promise
都解决或拒绝后才继续。
const promise1 = Promise.resolve("成功"); const promise2 = Promise.reject("失败"); Promise.allSettled([promise1, promise2]).then(results => { console.log(results); // [{status: "fulfilled", value: "成功"}, {status: "rejected", reason: "失败"}] });
- 接受一个
-
Promise.any()
- 接受一个
Promise
对象的数组,只要有一个Promise
被解决,就继续,只有在所有Promise
都被拒绝时才会失败。
const promise1 = Promise.reject("失败"); const promise2 = Promise.resolve("成功"); Promise.any([promise1, promise2]).then(result => { console.log(result); // 成功 }).catch(error => { console.error(error); });
- 接受一个
总结
Promise
是一种强大的工具,用于简化异步操作的处理。它的三种状态和多种方法使得开发者可以灵活地管理异步操作的成功和失败情况,在实际开发中广泛应用。
具体案例
好,我们可以通过 fetch
API 来模拟向 https://www.baidu.com/
这个接口发起请求,并使用 Promise
处理响应数据。虽然 https://www.baidu.com/
实际上并不允许跨域请求,我们可以假设这个请求是成功的,并展示如何处理请求的结果。
示例代码
function fetchBaiduData() {
return new Promise((resolve, reject) => {
fetch('https://www.baidu.com/')
.then(response => {
if (!response.ok) {
// 如果响应状态码不是 2xx,就拒绝这个 Promise
reject('请求失败,状态码:' + response.status);
} else {
// 否则,解析响应体为文本
return response.text();
}
})
.then(data => {
resolve(data); // 请求成功,返回解析后的数据
})
.catch(error => {
reject('请求失败,错误信息:' + error); // 捕获 fetch 过程中的任何错误
});
});
}
// 使用 Promise 处理请求结果
fetchBaiduData()
.then(data => {
console.log('请求成功,获取到的数据:', data);
})
.catch(error => {
console.error('请求失败:', error);
})
.finally(() => {
console.log('请求完成,无论成功或失败都会执行');
});
代码解释
-
创建 Promise:
- 在
fetchBaiduData
函数中,我们使用fetch
API 向https://www.baidu.com/
发起请求。 fetch
本身返回一个Promise
,我们使用.then
方法处理响应。
- 在
-
处理响应:
- 如果响应的状态码不在
200-299
范围内,我们会通过reject
方法拒绝这个Promise
,并传入错误信息。 - 如果请求成功,我们通过
response.text()
方法将响应体解析为文本(也可以使用response.json()
方法解析为 JSON 格式,视情况而定)。
- 如果响应的状态码不在
-
链式处理:
- 如果解析成功,调用
resolve
将解析后的数据传递给下一个then
处理。 - 如果在请求或解析过程中出现错误,则捕获到
catch
中,并通过reject
返回错误信息。
- 如果解析成功,调用
-
使用 Promise:
- 我们调用
fetchBaiduData
函数,并通过then
方法处理成功的请求结果,打印数据到控制台。 - 如果请求失败,
catch
方法会捕获错误并输出错误信息。 - 无论请求成功或失败,
finally
方法都会执行,用于执行收尾操作。
- 我们调用
在项目中的应用
笔灵web,360联运,支付功能接入
export function getPayQrcode360(params: QRCodeParams): Promise<ShutuResponse<any>> {
return new Promise((resolve, reject) => {
request
.post<
QRCodeParams,
ShutuResponse<{
app_id: string;
app_secret?: string;
...
}>
>(`${prefix.shutu}/pay/san60-pay-vip-build`, params)
.then(({ code, data }) => {
// resolve(data);
const { app_id: appid, qid } = data;
// @ts-ignore
window.SDK360.init({ ...});
// @ts-ignore
window.SDK360.createOrder(
{
order_id: data.out_trade_no,
...
},
(res: any) => {
if (res.errno === 0) {
resolve({ code, data: { ...res.data,..., out_trade_no: data.out_trade_no }, msg: '' });
} else {
reject({ code: 101, msg: res.errmsg });
}
},
(res: any) => {
console.log(res);
},
);
});
});
}
注意这里返回的也是Promise对象
import request from '@/utils/fetch';
export const getPayVipPolymerizePriceList = async () => {
return request.get<any, Sh。。。onse<PriceList>>(${prefix.shutu}/pay/pay-vip。。。price-list);
};
因为request.get是用axios 创建的请求实例,axios 是一个非常流行的 HTTP 客户端,它本身的请求方法(如 get, post 等)都是异步的,并返回 Promise 对象。