首先声明想要记录这个东西上下文。在之前只用过fetch和ajax,就是网络请求的时候一般都是fetch().then().catch()这样的promise链式调用,然而项目里面看见的api接口访问长这样
1 | apiCaller(){ fetch(url)}; |
try catch好说,啥语言都有的语法,但是这个await是个啥….8说了,查资料去…
async await
首先,async和await使用方法。await必须在async方法内,当执行到await时候,await后面的语句会在await语句执行完之后执行。还有就是await 执行完赋予变量是Promise.resolve()里面的值,如果有error则直接进catch。
咱先搞个demo试试,首先我不加await关键字
1 | const excuteAfterOneSec = () => { |
得到的结果是先打印了2再打印1。删掉await之后,就先打印了1,再打印2。就不放置结果了….
await是这样的,那么async这个关键字表示了啥啊,首先async这个方法表示函数是异步的(尼玛的,废话)…其次,async修饰的函数返回的是一个promise…上述example函数打印出来长这样。
正常来说我这个函数没有定义返回值,我打印出来的值应该是个undefined。然而打印出来一个Promise…而且在函数内如果有await的话,那么返回的promise在await执行完毕之前状态为pending,如果没有await的话,返回的是一个状态确定的promise。如下
1 | const example = async () => { |
这里的example相当于返回的Promise.resolve(undefined)。所以这个特性有啥用呢…俺也不知道,俺也没碰到….咱只知道下面这种情况有问题。
1 | Ids.map( async id =>await fetch(id)); |
网上比较一致的说法是,当你需要某个数组逐步执行的时候,以下写法是错的….为啥呢,因为await只会阻塞map里面callback,但是并不会阻塞map函数,所以当map结束之后,并不能保证我所有阻塞函数都完成了,正确的要咋整呢。那就要看promise了呀,如下所示
1 | example = async () =>{ |
辣么,接下来就讲讲关于Promise的东西。
Promise
说到Promise,其实最开始知道Promise是因为实习的时候用angular,然后官方tutorial直接使用的fetch。然后就从原本的
1 | $.ajax({ |
演变成了
1 | fetch(url).then(response => response.json()).then(data => excuteData(data)).catch(); |
那么,Promise咋用呢,上面哪两个函数其实差不多了
1 | const promise1 = new Promise((resolve,reject) => { |
这里面会在resolve执行之后执行then方法,并且传入resolve的参数,会作为then的callBack的参数(所以这里then里面的data就是’foo’了),同时then()也会返回一个Promise,像这里的return data.length,其实返回的是一个Promise.resolve(data.length)。
所以呢,data.length又会作为参数传到下一个then(这里的then里面的length就是foo的length 等于 3)。而catch方法在被reject的时候调用。如果出现这样的返回,就进的catch方法,如下
1 | const promise1 = new Promise((resolve,reject) => { |
自己运行一下就可以发现在第一个then中出现error之后不执行第二个then,直接执行了catch。
那么问题又来了,Promise和async/await有啥关系呢…事实上,async/await是generator和promise的一个语法糖。如下所示(其实没用到过generator..所以不知道这玩意儿有啥用)。
1 | const example = async () => { |
为什么
之前刚刚接触promise的时候好奇过一段时间,原本用ajax之类的方法,然后在访问接口之后执行回调函数,已经是很方便了呀,我为啥要用promise,还有现在的这个async/await?
我特么现在终于是知道了,当我需要访问三个接口,我需要三个接口全通之后再进行操作(这样的设计是很多的….)我如果用回调函数的话就会陷入回调地狱..
$.ajax({
url:`${firstUrl}`,
success:() =>{
$.ajax({
url:`${secondUrl}`,
success:() => {
$.ajax({
url:`${thirdUrl}`,
success:() => {finalExcute()} ,
error:()=>{console.log(error)}
})
}
error:()=>{console.log(error)}
})
}
error:(error) => {console.log(error)}
})
不说有多难看,我即使接口方面没有依赖我依然必须顺序执行…要是接口响应很慢,一个加载等一年?要是碰到上面那个需要十个接口全部访问之后再执行的功能,画面太美不敢看……
针对于这种写法,对于没有接口返回数据依赖的接口promise完全可以用Promise.All解决回调地狱,而且人家还可以用catch来统一处理异常,多个接口访问后执行的实现也更加优雅有效率,而且链式调用用这也比回调函数舒服。
async/await最爽了,至少在代码层面上看着非常的清爽,避免回调,用try catch处理异常(在这之前写js我根本用不到try catch这个语法的)…
其实之前看前端面试题啥的,深入promise,async/await,setTimeout的话会扯到eventLoop,关于eventloop的内容请见如下内容[https://tommy0121.github.io/2020/07/31/javascript-event/](https://tommy0121.github.io/2020/07/31/javascript-event/)