Promise到底是个啥玩意

大勇玩转科技2024-10-28 06:51:00  120

1. 回调地域

在学习 Promise 之前,我们先看一下什么是回调地狱:

这里我们模拟三个请求接口:

获取产品类别

// 1. 获取类别信息const getCategory = => { // 模拟请求 let res = { code: 200, message: "请求成功", data: [ { id: 1, name: "水果" }, { id: 2, name: "图书" }, ], }; return res;};

根据类别 id 获取产品信息

// 2. 根据类别 id 获取产品信息const getProductByCategoryId = (categoryId) => { // 模拟请求 let res = { code: 200, message: "请求成功", data: [ { id: 111, categoryId: 1, name: "苹果" }, { id: 112, categoryId: 1, name: "香蕉" }, { id: 113, categoryId: 1, name: "百香果" }, ], }; return res;};

根据产品 id 获取产品价格

// 3. 根据产品id获取产品价格const getPriceByProductId = (productId) => { // 模拟请求 let res = { code: 200, message: "请求成功", data: { id: 1001, productId: 111, price: 112.23, unitPrice: 1235.23 }, }; return res;};

接下来我们去获取第一个类别下第一个产品的单位价格信息:

let unitPrice = 0.0;// 获取产品价格const getProductPrice = => { let categoryRes = getCategory; if (categoryRes.code === 200) { let produceRes = getProductByCategoryId(1); if (produceRes.code === 200) { let priceRes = getPriceByProductId(1); if (priceRes.code === 200) { unitPrice = res.data.unitPrice; } } }};

我们发现在 getProductPrice 这个方法中,第一个请求接口的结果要作为第二个请求接口的参数,以此类推就会出现层层嵌套,回调里面套回调,这就是所谓的“回调地狱”。

如果请求的接口太多,那代码写起来可就太苦逼了,就跟套娃一样。

所以为了解决回调地狱的问题,提高代码的可读性,Promise 应运而生。

2. 邂逅 Promise

Promise 是异步编程的一种解决方案。它本质上是一个构造函数,可以构建一个 Promise 对象。

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject 。对象上有 then、catch、finall 方法。

Promise 有三种状态:pending、fulfilled、rejected:

pending:它的意思是待定的,相当于是一个初始状态。创建 Promise 对象时就是一个初始状态。

fulfilled:成功。当调用 resolved 方法后,Promise 对象的状态就会从 pending 切换到 fulfilled,且不可改变。

rejected:失败。当调用 reject 方法后,Promise 对象的状态就会从 pending 切换到 reject,且不可改变。

看了上面的解释,你可能还是有点懵逼,接下来我用通俗易懂的语言解释一下 Promise 是个什么玩意:

1.Promise 就是一个用来封装 HTTP 请求的工具。

2.我们请求后台接口获取数据,如果请求成功,就调用 Promise 的 resolve 方法,并将返回的数据作为该方法的参数。如果请求失败,就调用 Promise 的 reject 方法,并将返回的错误信息作为该方法的参数。

3.然后我们将一个 Promise 对象作为该请求接口的返回值返回。

4.因为该接口返回一个 Promise 对象,所以我们调用该接口的时候就可以直接用.then处理成功的信息,用 .catch 处理失败的信息了。

接下来我们将上面的例子用 Promise 改造一下,有了真实案例,大家对 Promise 的理解就更清晰明了了。

3. 使用 Promise

获取类别信息

const getCategory = => { // 返回结果封装成 Promise 对象 return new Promise((resolve, reject) => { // 模拟请求 let res = { code: 200, message: "请求成功", data: [ { id: 1, name: "水果" } ], }; if (res.code == 200) { resolve(res); } else { reject(res); } }); };

根据类别 id 获取产品信息

const getProductByCategoryId = (categoryId) => { return new Promise((resolve, reject) => { // 模拟请求 let res = { code: 200, message: "请求成功", data: [ { id: 111, categoryId: 1, name: "苹果" }, { id: 112, categoryId: 1, name: "香蕉" }, { id: 113, categoryId: 1, name: "百香果" }, ], }; if (res.code == 200) { resolve(res); } else { reject(res); } }); };

根据产品 id 获取产品价格

const getPriceByProductId = (productId) => { return new Promise((resolve, reject) => { // 模拟请求 let res = { code: 200, message: "请求成功", data: { id: 1001, productId: 111, price: 112.23, unitPrice: 1235.23 }, }; if (res.code == 200) { resolve(res); } else { reject(res); } }); };

4.获取第一个类别下第一个产品的单位价格信息

Promise 最常用的就是链式调用格式:

let unitPrice = 0.0; // 获取产品价格 const getProductPrice = => { getCategory.then(res => { // 类别 id let id = res.data[0].id; // 返回一个 Promise 对象 return getProductByCategoryId(id); }).then(res => { // 产品 id let id = res.data[0].id; return getPriceByProductId(id); }).then(res => { unitPrice = res.data.unitPrice; }) };

当然我们在日常使用过程中一般都是这种格式:

getMethod.then(res => { // 请求成功 }).catch(error=>{ // 异常 }).finally(=>{ // 不管成功还是异常都要执行 })

4. async 和 await

虽然有了 Promise 之后,代码的可读性有了很大提高。但是 ES7 又引入了 async 和 await 来简化 Promise 调用操作,实现了以异步操作像同步的方式去执行。

说白了async 和 await 就是对 Promise 进行了封装

语法:

await 和 async 是成对出现的,如果写了 await 必须要写 async,否则会报错。如果只写 async,那返回的就是一个 Promise 对象

举例:

let unitPrice = 0.0;// 获取产品价格const getProductPrice = async => { let res1 = await getCategory; let categoryId = res1.data[0].id; let re2 = await getProductByCategoryId(categoryId); let productId = re2.data[0].id; let re3 = await getPriceByProductId(productId); unitPrice = res3.data.unitPrice;};

如果只写 async,返回的就是一个 Promise 对象

const getProductPrice = async => { getCategory.then(res=>{ let categoryId = res.data[0].id })};const getCategory = async => { // 模拟请求 let res = { code: 200, message: "请求成功", data: [ { id: 1, name: "水果" }, { id: 2, name: "图书" }, ], }; return res;};

那为什么说 async 和 await 实现了异步编程同步化呢?

因为 await 这个命令的意思就是等这一行的异步方法执行成功后,然后才能执行下一行代码,否则就一直等待,下面的代码就执行不了。

所以虽然请求后台的接口是异步的,但是 await 在语法层面实现了同步。

5. 答疑

5.1 同步请求和异步请求

同步请求:当发送一个同步请求时,会暂停后面的代码执行,等待请求的返回结果,然后再继续执行下一行代码。

异步请求:当发送一个异步请求时,会继续执行后面的代码而不会等待请求的返回结果。当请求完成后,再通过回调函数或事件处理函数来处理返回的数据。

1.同步请求就会依次打印:1、2。如果第一个方法执行时间比较长,那就一直等待。

const getProductPrice = => { console.log("1")};console.log("2")

2.异步请求可能会先打印 2,后打印 1。

const getProductPrice = async => { console.log("1")};console.log("2")

5.2 promise 和 axios 什么关系

Promise 是 JavaScript 中用于异步编程的一个对象,而 axios 是 用来发送 HTTP 请求的工具库。

Promise 对 axios 的返回结果进行了封装。所以当你发送一个 axios 请求,会返回一个 Promise 对象。然后你就可以调用 .then、.catch方法了。

5.3 promise 和 async/await 什么关系

1.async/await 对 promise 进行了封装。

2.async/await 是用同步语法去获取异步请求,彻底消灭回调函数。

3.只有 async,返回的是 Promise 对象。

4.await 相当于 Promise 的 then

转载此文是出于传递更多信息目的。若来源标注错误或侵犯了您的合法权益,请与本站联系,我们将及时更正、删除、谢谢。
https://www.414w.com/read/1421868.html
0
最新回复(0)