• 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')
    }        
  • 相关阅读:
    优先队列
    Problem W UVA 662 二十三 Fast Food
    UVA 607 二十二 Scheduling Lectures
    UVA 590 二十一 Always on the run
    UVA 442 二十 Matrix Chain Multiplication
    UVA 437 十九 The Tower of Babylon
    UVA 10254 十八 The Priest Mathematician
    UVA 10453 十七 Make Palindrome
    UVA 10163 十六 Storage Keepers
    UVA 1252 十五 Twenty Questions
  • 原文地址:https://www.cnblogs.com/meiyanstar/p/14776746.html
Copyright © 2020-2023  润新知