异步同步化( Promise 详解)

ES 6 Promise的用法

一 、为什么要使用Promise

“ 回调地狱 ”这个词,不知道大家听过没有,就是异步调用获取到结果后,

为下一个异步函数提供 参数,所以就会一层一层的出现回调里面 嵌入回调,导致层次很深,代码维护起来特别的复杂,看一下下面的小案例大家就知道什么意思了。

以uni.request( ) 为例

下面的举例就 以uniapp里面的网络请求uni.request()为例了,

如果你做的是微信小程序wx.request()也是一样的,还有jQuery的ajax(),

这些都是异步请求

通过success回调函数获取数据的,

那有童鞋会问为什么不适用vue的axios那,因为axios网络请求已经封装了promise了。

getData(){
  //获取分类列表id
  uni.request({
    url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
    success:res=>{
      let id=res.data[0].id
      // 根据分类id获取该分类下的所有文章
      uni.request({
        url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
        data:{
          cid:id
        },
        success:res2=>{
          //获取到一篇文章的id,根据文章id找到该文章下的评论
          let id=res2.data[0].id;
          uni.request({
            url:"https://ku.qingnian8.com/dataApi/news/comment.php",
            data:{
              aid:id
            },
            success:res3=>{
              //找到该文章下所有的评论
              console.log(res3)
            }
          })
        }
      })

    }
  })
}

大家看到上的代码了没有,数一数有几层嵌套,出现了几个success回调,这个案例的嵌套还算是少的那,还有比这更夸张的,这就是所谓的回调地狱,层层嵌套,要是维护起这样的代码来,直接会把新手劝退的,自己写过的代码要是不加注释也不知道这到底是干嘛的。

在没有ES6的promise时候原来是怎么优化的那,把每一个request请求封装出一个函数将结果进行返回,这就是原来常用的回调函数方案,将上述代码可以改造成如下代码:

1 . 0 版本 ( 封装函数 )

调用部分 ↓

//在onload初始化后调用相应的函数
onLoad() {
  //调用导航函数,并拿到函数的返回值
  this.getNav(res=>{
    let id=res.data[0].id;
    //拿到分类id作为参数
    this.getArticle(id,res2=>{
      //拿到文章id作为参数
      let id=res2.data[0].id;
      this.getComment(id,res3=>{
        //最终获取到第一个分类下,第一篇文章下,所有评论
        console.log(res3)
      })
    })
  });
} 

**封装的函数部分↓ **

methods: {
    //先获取导航分类接口,将结果进行返回,到调用函数的地方获取
    getNav(callback){
      uni.request({
        url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
        success:res=>{
          callback(res)
        }
      })
    },

    //获取文章数据,将文章列表进行返回
    getArticle(id,callback){
      uni.request({
        url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
        data:{
          cid:id
        },
        success:res=>{
          callback(res)
        }
      })
    },

      //获取文章下的所有评论
      getComment(id,callback){
        uni.request({
          url:"https://ku.qingnian8.com/dataApi/news/comment.php",
          data:{
            aid:id
          },
          success:res=>{
            callback(res)
          }
        })
      }
} 

小结: 我们通过封装 方法 从而简化代码 让代码看起来更加清晰 ( 至少在看调用函数方面 会更加清晰 ), 但是并没有很好解决回调地狱的问题

二 、什么是 Promise

promise是解决异步的方法,本质上是一个构造函数,

可以用它实例化一个对象。对象身上有resolve、reject、all,原型上有then、catch方法。

promise对象有三种状态:

pending(初 识状态/进行中)、resolved或fulfilled(成功)、rejected(失败)

下面我们直接打印一下 Promise

console.dir(Promise) 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mVlwddYH-1675075189316)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130121411121.png)]

三 、将回调函数修改为 Promise 方案
2.0 版本 ( Promise 对象 )

.then 的链式调用函数

//promise链式调用
this.getNav().then(res=>{
  let id=res.data[0].id;
  return this.getArticle(id);
}).then(res=>{
  let id=res.data[0].id;
  return this.getComment(id)
}).then(res=>{
  console.log(res)
}) 

函数封装也需要进行修改

methods: {
    //先获取导航分类接口,将结果进行返回,到调用函数的地方获取
    getNav(callback){
      return new Promise((resolve,reject)=>{
        uni.request({
          url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
          success:res=>{
            resolve(res)
          },
          fail:err=>{
            reject(err)
          }
        })
      })
    },


    //获取文章数据,将文章列表进行返回
    getArticle(id){
      return new Promise((resolve,reject)=>{
        uni.request({
          url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
          data:{
            cid:id
          },
          success:res=>{
            resolve(res)
          },
          fail:err=>{
            reject(err)
          }
        })
      })
    },

      //获取文章下的所有评论
      getComment(id){
        return new Promise((resolve,reject)=>{
          uni.request({
            url:"https://ku.qingnian8.com/dataApi/news/comment.php",
            data:{
              aid:id
            },
            success:res=>{
              resolve(res)
            },
            fail:err=>{
              reject(err)
            }
          })
        })
} 

看完上面两段代码 , 下面我们进行详细的分析

很多初学者不是很清楚 .then 以及里面的一些参数等等
下面, 我们结合 上面的案例进行讲解
首先, 在上面, 我们通过 console.log(Promise) 可以知道里面
包括了 then() catch() 等方法
所以我们要原来的调用函数的返回值 改成
返回 Promise 对象
在此之前我们需要对 // 对象 进行实例化 
如下面:
getNav(callback){
      return new Promise((resolve,reject)=>{ 
      ........
      })
},
// 也可以下面这种写法
getNav(callback){
    // 实例化
      let p = new Promise((resolve,reject)=>{ 
      ........
      })
      return p
},

有关于实例化 Promise 中的两个参数 (resolve,reject)

// 和 1.0 版本中 callblack 的作用差不多 主要起了回调数据的作用
// 不过, resolve 是表示运行成功的返回的数据  reject是表示运行失败返回的数据
 getNav(callback){
      return new Promise((resolve,reject)=>{
        uni.request({
       	  ........,
          success:res=>{
            resolve(res)
          },
          fail:err=>{
            reject(err)
          }
        })
      })
    }, 
四、await / async ES7的新规范,异步处理同步化

注意

// await / async 两者需要一起使用, 才能起作用, 缺一不可
如果使用了await 没有在函数中使用async 命令, 就会报错
如果使用了async 没有使用await 不会报错 但没有意义
3 . 0 版本
async onLoad() {
  let id,res;
  res=await this.getNav();
  id=res.data[0].id;
  res=await this.getArticle(id);
  id=res.data[0].id;
  res=await this.getComment(id);
  console.log(res)
} 

关于封装函数部分和 then的链式调用的封装的代码一样

特别声明: 本文章并非本人完全原创, 只是对虾米老师的笔记进行简化以及添加一些自己的见解
还有就是 如果笔记有什么问题, 欢迎大家在评论区或者私信或者我们的交流群斧正。
我也是小白,希望和大家一起进步。
最后祝大家新年快乐!!!! 

课程链接: https://www.bilibili.com/video/BV1XW4y1v7Md?share_source=copy_web

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值