1. 回调地域在学习 Promise 之前 , 我们先看一下什么是回调地狱:
这里我们模拟三个请求接口:
- 获取产品类别
// 1. 获取类别信息const getCategory = () => {// 模拟请求let res = {code: 200message: \"请求成功\"data: [{ id: 1 name: \"水果\"{ id: 2 name: \"图书\"
;return res;;
- 根据类别 id 获取产品信息
// 2. 根据类别 id 获取产品信息const getProductByCategoryId = (categoryId) => {// 模拟请求let res = {code: 200message: \"请求成功\"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: 200message: \"请求成功\"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. 邂逅 PromisePromise 是异步编程的一种解决方案 。 它本质上是一个构造函数 , 可以构建一个 Promise 对象 。
Promise 构造函数接受一个函数作为参数 , 该函数的两个参数分别是 resolve 和 reject。 对象上有 then、catch、finall 方法 。
Promise 有三种状态:pending、fulfilled、rejected:
- pending:它的意思是待定的 , 相当于是一个初始状态 。 创建 Promise 对象时就是一个初始状态 。
- fulfilled:成功 。 当调用 resolved 方法后 , Promise 对象的状态就会从 pending 切换到 fulfilled , 且不可改变 。
- rejected:失败 。 当调用 reject 方法后 , Promise 对象的状态就会从 pending 切换到 reject , 且不可改变 。
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: 200message: \"请求成功\"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: 200message: \"请求成功\"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: 200message: \"请求成功\"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 => {// 类别 idlet id = res.data[0
.id;// 返回一个 Promise 对象return getProductByCategoryId(id);).then(res => {// 产品 idlet 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: 200message: \"请求成功\"data: [{ id: 1 name: \"水果\"{ id: 2 name: \"图书\"
;return res;;
那为什么说 async 和 await 实现了异步编程同步化呢?因为 await 这个命令的意思就是等这一行的异步方法执行成功后 , 然后才能执行下一行代码 , 否则就一直等待 , 下面的代码就执行不了 。
所以虽然请求后台的接口是异步的 , 但是 await 在语法层面实现了同步 。
5. 答疑5.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 对象 。
【Promise到底是个啥玩意】4.await 相当于 Promise 的 then
推荐阅读
- 鸿蒙系统:到底好在哪里?体验后说说我的总结
- 酒店订房“订后即焚”,网友质疑:这功能到底在保护什么?平台最新回应
- 高通骁龙8?至尊版移动平台,深度解析,它到底有哪些看点?
- 4699元的小屏手机,vivo X200 Pro mini用起来到底咋样?
- 骁龙8至尊版已发布:对比天玑9400处理器,到底有多少不同?
- 今年是个换旗舰手机的好机会,骁龙8至尊版牙膏挤爆!
- 小屏手机到底有没有市场?摩托罗拉又想花式秀操作!
- 荣耀X60系列已正式发布:对比荣耀X50系列,到底有多大提升?
- 超高端战苹果,唯华为可行,其它都不是个
- 不管流畅还是个性化,ColorOS 15全都有