Promise Async

  首先声明想要记录这个东西上下文。在之前只用过fetch和ajax,就是网络请求的时候一般都是fetch().then().catch()这样的promise链式调用,然而项目里面看见的api接口访问长这样

1
2
3
4
5
6
7
8
9
apiCaller(){ fetch(url)};

async aplClient(){
try{
const result = await apiCaller();
}catch(error){
doErrorExcution(error);
}
}

  try catch好说,啥语言都有的语法,但是这个await是个啥….8说了,查资料去…

async await

  首先,async和await使用方法。await必须在async方法内,当执行到await时候,await后面的语句会在await语句执行完之后执行。还有就是await 执行完赋予变量是Promise.resolve()里面的值,如果有error则直接进catch。
  咱先搞个demo试试,首先我不加await关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 const excuteAfterOneSec = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve('1');
console.log('1 sec');
}, 1000);
})
}
const excuteAfterTwoSec = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve('2');
console.log('2 sec');
}, 2000);
})
};
const example = async () => {
await excuteAfterTwoSec();
await excuteAfterOneSec();
}
console.log(example());

  得到的结果是先打印了2再打印1。删掉await之后,就先打印了1,再打印2。就不放置结果了….
  await是这样的,那么async这个关键字表示了啥啊,首先async这个方法表示函数是异步的(尼玛的,废话)…其次,async修饰的函数返回的是一个promise…上述example函数打印出来长这样。
example

  正常来说我这个函数没有定义返回值,我打印出来的值应该是个undefined。然而打印出来一个Promise…而且在函数内如果有await的话,那么返回的promise在await执行完毕之前状态为pending,如果没有await的话,返回的是一个状态确定的promise。如下

1
2
3
4
5
const example = async () => {
excuteAfterTwoSec();
excuteAfterOneSec();
}
console.log(example());

  这里的example相当于返回的Promise.resolve(undefined)。所以这个特性有啥用呢…俺也不知道,俺也没碰到….咱只知道下面这种情况有问题。

1
Ids.map( async id =>await fetch(id));

  网上比较一致的说法是,当你需要某个数组逐步执行的时候,以下写法是错的….为啥呢,因为await只会阻塞map里面callback,但是并不会阻塞map函数,所以当map结束之后,并不能保证我所有阻塞函数都完成了,正确的要咋整呢。那就要看promise了呀,如下所示

1
2
3
4
example = async () =>{
const promises = Ids.map(id => fetch(id))
const result = await Promise.all(promises);
}

  辣么,接下来就讲讲关于Promise的东西。

Promise

  说到Promise,其实最开始知道Promise是因为实习的时候用angular,然后官方tutorial直接使用的fetch。然后就从原本的

1
2
3
4
$.ajax({
success:function(){};
error:function() {};
})

演变成了

1
fetch(url).then(response => response.json()).then(data => excuteData(data)).catch();

  那么,Promise咋用呢,上面哪两个函数其实差不多了

1
2
3
4
5
6
7
8
9
const promise1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
promise1
.then(data => {console.log(data); return data.length})
.then(length => console.log(length))
.catch();

  这里面会在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
2
3
4
5
6
7
8
9
const promise1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
promise1
.then(data => {console.log(data); return data.length})
.then(length => console.log(length))
.catch(data =>console.log(data));

  自己运行一下就可以发现在第一个then中出现error之后不执行第二个then,直接执行了catch。
  那么问题又来了,Promise和async/await有啥关系呢…事实上,async/await是generator和promise的一个语法糖。如下所示(其实没用到过generator..所以不知道这玩意儿有啥用)。

1
2
3
4
5
6
7
8
 const example = async () => {
await excuteAfterTwoSec();
await excuteAfterOneSec();
}
// 等价于
const example = async () => {
excuteAfterTwoSec().then(() => excuteAfterOneSec());
}

为什么

  之前刚刚接触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/)