ES8新特性(2017)-- async/await详细介绍与使用

ES8(2017)标准引入了async函数,async/await是ES8提出的基于Promise的解决异步的最终方案。

一、async关键字

async作为一个关键字放到函数前面,用于表示函数是一个异步函数。

因为async就是异步的意思,也就表示 该函数的执行不会阻塞后面代码的执行

下面是一个async函数:

async function() timeout(){
   return 'hello world';
}
//语法就是在函数前面加上async关键字来表示它是异步的。

例1:async的执行不会阻塞它后面的代码

1 async function timeout () {
2       return 'hello world'
3 }
4 
5 timeout();
6 console.log('虽然我在后面,但是我先执行了')
7 
8 //输出结果:

 虽然第五行调用了timeout(),但是没有任何输出。接下来我们将timeout()改成 console.log(timeout())

例2:

1 async function timeout () {
2       return 'hello world'
3 }
4  
5 console.log(timeout());
6 console.log('虽然在后面,但是我先执行了')
7 //输出结果:

第五行打印出来可以看出async函数返回的是一个promise对象,如果要获取到promise返回值,我们应该用then方法。

例3:

1 async function timeout(){
2    return 'hello world'
3 }
4 
5 timeout().then(result =>{
6      console.log(result);
7 })
8 console.log('虽然在后面,但是我先执行');
//输出结果:

例3的代码中获取到了“hello world”,同时timeout的执行也没有阻塞后面代码的执行。

例4:在例2代码中,控制台打印的timeout()结果中Promise有一个resolved,这是async函数内部的实现原理。如果async函数中有返回一个值,当调用该函数时,内部会调用Promise.solve()方法把它转化成一个promise对象作为返回,但如果timeout内部抛出错误呢?那么就会调用Promise.reject()返回一个promise对象,这是修改一下timeout函数:

async function timeout(flag) {
    if (flag) {
        return 'hello world'
    } else {
        throw 'my god, failure'
    }
}
console.log(timeout(true))  // 调用Promise.resolve() 返回promise 对象。
console.log(timeout(false)); // 调用Promise.reject() 返回promise 对象。
//输出结果:

如果函数内部抛出错误,promise对象有一个catch方法进行捕获。

timeout(false).catch(err =>{
       console.log(err)
})

二、await关键字

注意:await 关键字只能放到async 函数里面

await是等待的意思,①那么他等待的是什么?

②它后面跟着什么呢?(其实他后面可以放任何表达式,不过我们更多的是放一个返回promise对象的表达式。)

 例1:现在写一个函数,让它返回promise 对象,该函数的作用是2s 之后让数值乘以2

 1 //2s 之后返回双倍的值
 2 function doubleAfter2seconds(num){
 3    return new Promise((resolve,reject) =>{
 4           setTimeout(() => {
 5                resolve(2 * num)
 6            },2000);
 7    })
 8 }
 9 
10 async function testResult(){
11     let result = await doubleAfter2seconds(30);
12     console.log(result);
13 }
14 //输出结果:
15 //调用testResult函数,2s后输出60

此段例1代码的执行过程:

①:调用testResult函数,它里面遇到了await,await表示等待,此时代码暂停在这里,不再向下执行,

②:那么①中await在等什么呢?等后面的promise对象执行完毕,然后拿到promise中resolve的值并返回,拿到返回值后,再继续向下执行。以上述例1中的代码为例,在第11行中遇到await后,代码暂停执行,等待doubleAfter2seconds(30)执行完毕,doubleAfter2seconds(30)返回的promise(line3)开始执行,2s后执行第5行resolve,并返回了值60。这时line11中才拿到返回值60,然后赋值给result,此时暂停的状态结束。

③:代码继续执行下面的console.log()语句

例2:就这一个函数,我们可能看不出async/await 的作用,如果我们要计算3个数的值,然后把得到的值进行输出呢?

async function testResult() {
    let first = await doubleAfter2seconds(30);
    let second = await doubleAfter2seconds(50);
    let third = await doubleAfter2seconds(30);
    console.log(first + second + third);
}

//输出结果:
//6s后,控制台输出220

至此,我们可以看到,写异步代码就像写同步代码一样了,再也不需要像以前一样,等一个方法的回调之后执行的需要写到这个方法的回调方法里面,这样就方便多了。

三、总结

  1. async和await基本是组合使用的,async用来声明一个异步方法,返回的是一个promise对象,如果要获取到对应的返回值,就需要使用.then方法;
  2. await只能在async方面的里面使用,让后面的执行语句或方法要等待当前await方法的结果后才能再执行。

 四、当async+await遇见forEach和for···of

 1 //定义一个fetch函数模拟异步请求
 2 function fetch(x){
 3    return new Promise((resolve,reject) => {
 4        console.log('aaa');
 5        setTimeout(() =>{
 6            resolve(x)
 7       },500 * x)
 8    })
 9 }
10 
11 //第一题:
12 function test(){
13     let arr = [3,2,1]
14     arr.forEach(async item =>{
15         const res = await fetch(item)
16         console.log(res)
17     })
18     console.log('end')
19 }
20 test();
21 //输出结果:aaa,aaa,aaa,end,1,2,3
22 
23 //第二题
24 async function test(){
25      let arr = [3,2,1]
26      for(const item of arr){
27           const res = await fetch(item)
28           console.log(res)
29      }
30      console.log('end')
31 }
32 test()
33 //输出结果:aaa,3,aaa,2,aaa,1,end

为什么同样是遍历,输出结果却不一样呢?

因为for...of内部处理的机制和forEach不同,forEach是直接调用回调函数,for...of是通过迭代器的方式去遍历。

foreach的处理机制:

//参考下 Polyfill 版本的 forEach,简化后的伪代码:
while(index < arr.length){
    //也就是我们传入的回调函数
    callback(item,index)
}

for...of的处理机制

//使用迭代器写第二题(既for...of码的语法糖)等价于:
async function test(){
     let arr = [3,2,1]
     const iterator = arr[Symbol,iterator]()   //for of 会自动调用遍历器函数
     let res = itertor.next()
     while(!res.done){
            const value = res.value
            const res1 = await fetch(value)
            console.log(res1)
            res = iterator.next()
     }
     console.log('end')
}        
原文地址:https://www.cnblogs.com/meiyanstar/p/14776746.html