zoukankan      html  css  js  c++  java
  • 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')
    }        
  • 相关阅读:
    MongoDB +JSON+JQuery.Pagination+Linq 实现无刷新分页
    DBHelper
    C# .Net动态调用webService
    .net 将图片文件转换成流输出到浏览器
    将mongodb作为服务
    .net 最简单文件上传支持跨服务器
    Windows Phone 7
    javascript中对Date类型的常用操作
    DataTable 转换JSON
    C# 实现 MemCache 监控管理工具
  • 原文地址:https://www.cnblogs.com/meiyanstar/p/14776746.html
Copyright © 2011-2022 走看看