Promise
为什么要使用 Promise
“回调地狱”这个词,不知道大家听过没有,就是异步调用获取到结果后,为下一个异步函数提供参数,所以就会一层一层的出现回调里面嵌入回调,导致层次很深,代码维护起来特别的复杂,看一下下面的小案例大家就知道什么意思了。 下面的举例就以 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 请求封装出一个函数将结果进行返回,这就是原来常用的回调函数方案,将上述代码可以改造成如下代码: 调用部分 ↓
//在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) } }) }}看上面大家可能都看懵了,仔细看来,并没有解决回调地狱的问题,还是回调里面嵌套回调,只是把函数独立出来了,看着清晰条理了一些而已,但是维护难度还是有的,说以随着 ES6 的普及,这种方案逐渐边缘化,取而代之的就是 promise 方案了。
什么是 promise
promise 是解决异步的方法,本质上是一个构造函数,可以用它实例化一个对象。对象身上有 resolve、reject、all,原型上有 then、catch 方法。promise 对象有三种状态:pending(初识状态/进行中)、resolved 或 fulfilled(成功)、rejected(失败)
- pending。它的意思是 “待定的,将发生的”,相当于是一个初始状态。创建 Promise 对象时,且没有调用 resolve 或者是 reject 方法,相当于是初始状态。这个初始状态会随着你调用 resolve,或者是 reject 函数而切换到另一种状态。

- resolved。表示解决了,就是说这个承诺实现了。 要实现从 pending 到 resolved 的转变,需要在 创建 Promise 对象时,在函数体中调用了 resolve 方法

- rejected。拒绝,失败。表示这个承诺没有做到,失败了。要实现从 pending 到 rejected 的转换,只需要在创建 Promise 对象时,调用 reject 函数。

将回调函数修改为 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)})函数返回 promise 对象
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) } }) }) }}经过一番改造,代码的可读性是不是更好了那,虽然多了几行代码,但是在调用的时候实在是太优雅了,清晰明了。
如果你觉得,这种调用方式还是有嵌套不够清晰,还有大杀器,就是目前最为流行的 await/async 了,这是 ES7 新引入的概念。
await / async ES7 的新规范,异步处理同步化
这两个命令是成对出现的,如果使用 await 没有在函数中使用 async 命令,那就会报错,如果直接使用 async 没有使用 await 不会报错,只是返回的函数是个 promise,可以,但是没有意义,所以这两个一起使用才会发挥出它们本身重要的作用。
这两个命令怎么用那,还是通过上面的案例,来该着一下 then 的链式调用代码。
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)}以上代码就是最终的改造版了,可以看到 onload 是函数,这个函数必须有 async 命令,在调用函数的部分,前面都加了一个 await,这个命令的意思就是等这一行的异步方法执行成功后,将返回的值赋值给 res 变量,然后才能再走下一行代码,这就是将原来的异步编程改为了同步编程,这就是标题提到的“异步处理,同步化”,
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

苏公网安备32021402002558号