promise 异步同步异步同步化

以网络请求为例,异步操作获取的结果作为下一个异步操作的参数时,这种层次越深,回调嵌入回调的次数越多,代码维护越复杂。

回调地狱

uniapp 中的 uni.request() , 微信小程序 中的 wx.request() 和 jQuery 中的 ajax() 都是异步请求,通过success回调函数获取数据。
vue 中的 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=>{
          let id=res2.data[0].id;
          //获取到一篇文章的id,根据文章id找到该文章下的评论  第三次发起请求
          uni.request({
            url:"https://ku.qingnian8.com/dataApi/news/comment.php",
            data:{
              aid:id
            },
            success:res3=>{
              //找到该文章下所有的评论
              console.log(res3)
            }
          })
        }
      })
    }
  })
}

这里一共三层嵌套,代码一大段,阅读起来比较困难。

封装使其便于阅读

通过封装函数可以让相同的代码阅读起来清晰一些。

//在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链式调用

ES6中引入的Promise可以很好的解决这个问题。

promise是解决异步的方法,本质上是一个构造函数,可以用它实例化一个对象。
对象身上有resolve、reject、all,原型上有then、catch方法。promise对象有三种状态:pending(初识状态/进行中)、resolved或fulfilled(成功)、rejected(失败)。

创建Promise对象时,且没有调用resolve或者是reject方法,相当于是初始状态。这个初始状态会随着你调用resolve,或者是reject函数而切换到另一种状态。
要实现从pending到resolved的转变,需要在 创建Promise对象时,在函数体中调用了resolve方法。
要实现从pending到rejected的转换,只需要在创建Promise对象时,调用reject函数。

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)
            }
          })
        })

}

//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)
})

promise的all方法:

p.all([p1,p2,p3])

p,p1,p2,p3都是promise实例。

p的状态由p1、p2、p3决定,分成两种情况。

只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

注意: 如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

promise 将多层嵌套改为了多次链式调用,条例变得清晰了。

async和await异步处理同步化

一般情况下,这两个命令是成对出现的,如果使用await没有在函数中使用async命令,那就会报错,如果直接使用async没有使用await不会报错,只是返回的函数是个promise,可以,但是没有意义,所以这两个一起使用才会发挥出它们本身重要的作用。

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)
}

await表示本行代码运行完毕后才进而运行下一行,所以三次请求会依次执行,将原来的异步编程改为了同步编程,这就是标题提到的“异步处理,同步化”。

总结:如果涉及到网络请求没有依赖关系的话,异步请求是效率最高的,但是下一个的方法依赖于上一个网络请求的结果,那么久必须使用await命令,将异步结果等待返回之后再执行后面的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值