Promise链式调用与async函数解决回调地狱问题
在平时我们使用vue的时候经常会看到在请求接口的时候总是会有async与await:
这是为什么呢?不能直接请求接口吗?
这里其实是为了避免出现回调地狱的问题。要理解清楚这个问题不妨从promise的链式调用开始讲起。
什么是回调地狱?
概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调地狱。
我们知道一个axios函数中包含一些url等请求参数和一个.then的回调函数,由于其异步性,一个接口的请求需要等到回调函数成功调回才算结束。于是要是我们在.then里面在嵌入一个axios函数的话就需要等到上一层请求后再进入这层,再由这层回调到上层。代码量一多,不仅可读性差而且异常无法捕获,耦合性严重,牵一发动全身。比如看下面代码:
1 |
|
我在第二个url中最后加了一个“!”让其错误,并让catch寻找错误的地方。然而我们发现:
其错误直接来源于axios的源码处,而且显示Uncaught (in promise),这就是回调地狱最直接的一个弊端处。
好了这里又涉及到一个词叫promise。
何为Promise?
mdn的解释是:“Promise是一个对象,它代表了一个异步操作的最终完成或者失败。”所以说Promise就是一个函数返回的对象,不然每次做回调操作都要自己手动传一个回调函数进去。
解释:依靠then()方法回返回一个新生成的Promise对象特性,继续串联下一环任务,直到结束。而then()回调函数中的返回值会影响新生成的Promise对象最终状态和结果。这样通过链式调用,可以有效解决回调函数嵌套问题。
1 |
|
可以看到我们创建了一个新的promise对象并赋值给p,然后再用p触发回调函数,并生成了一个全新的promise对象并赋值给p2。
在最后一行的log中,使用了三等判断进行比较,我们知道三等判断,判断的是两个变量保存的内存地址,最后其返回了false更可以说明生成的是一个全新的promise对象。
所以知道了promise的工作原理,我们就可以这样写:
1 |
|
没错,就是在第二个axios前面多了一个return,就可以捕获到第二层的错误了。
async函数和await
我们现在知道了promise可以解决回调地狱,但是这还是在回调函数里面不断嵌套,可读性极差,这时async函数(意思为“异步”)的引入就极大的改善了这个问题。
定义:async函数是使用async关机字声明的函数。async函数是AsyncFunction构造函数的实例,并且其中允许使用await关键词。async和await关键词让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。
因此我们只需要这样:
1 |
|
或者:
1 |
|
注意上面第二个代码中pname和cname没有用const定义,是因为当我在外面用
1 |
|
定义时发现报出错误:Assignment to constant variable(把常量赋值给了变量)
这是因为我们使用 const 定义了变量且存在初始值。 后面又给这个变量赋值,所以报错了。ES6 标准引入了新的关键字 const 来定义常量,const 与 let 都具有块级作用域:使用 const 定义的常量,不能修改它的值,且定义的常量必须赋初值;let 定义的是变量,可以进行变量赋值操作,且不需要赋初值。这个错误就是因为我们修改了常量而引起的错误,虽然某些浏览器不报错,但是无效果!所以解决方法就是前面加:
1 |
|
成功解决问题。
– 这里debug的时候发现const和let这块还有点含糊,const似乎最好是赋值一个对象或数组,再对对象进行赋值。等我哪天彻底搞明白了后单独出一期讲讲_(:3 ⌒゙)__