zoukankan      html  css  js  c++  java
  • 异步操作要了解的ES7的async/await

    1、什么是async、await?

    async顾名思义是“异步”的意思,async用于声明一个函数是异步的。而await从字面意思上是“等待”的意思,就是用于等待异步完成。并且await只能在async函数中使用。

    通常async、await都是跟随Promise一起使用的。为什么这么说呢?因为async返回的都是一个Promise对象同时async适用于任何类型的函数上。这样await得到的就是一个Promise对象(如果不是Promise对象的话那async返回的是什么 就是什么);

    await得到Promise对象之后就等待Promise接下来的resolve或者reject。

    我们先看个例子:

     1 var sleep = function (time) {
     2     return new Promise(function (resolve, reject) {
     3         setTimeout(function () {
     4             resolve();
     5         }, time);
     6     })
     7 };
     8 
     9 var start = async function () {
    10     // 在这里使用起来就像同步代码那样直观
    11     console.log('start');
    12     await sleep(3000);
    13     console.log('end');
    14 };
    15 
    16 start();

     上面代码控制台运行的结果是:先打印出‘start’,然后等待3秒后打印出“end”,这就是一个简单的async/await的例子。

    2、我们需要知道的是:

     1 1、async 表示这是一个async函数,await只能用在这个函数里面。
     2 
     3 2、async/await 是一种编写异步代码的新方法。之前异步代码的方案是回调和 promise。
     4 
     5 3、async/await 是建立在 promise 的基础上。
     6    await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…),
     7    await 表示在这里等待promise返回结果了,再继续执行。
     8 
     9 4、async/await 像 promise 一样,也是非阻塞的。
    10 
    11 5、async/await 让异步代码看起来、表现起来更像同步代码。这个是async/await 的真正威力,也可以说是其相比较promise的最大优点。

    3、首先了解async函数起什么作用

    1 async function test() {
    2   return "hello world";
    3 }
    4 
    5 const result = test();
    6 console.log(result);

    浏览器打印出来的是:Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello world"}

    想一下,如果async函数没有返回值呢?会是什么样?如下代码:

    1 async function test() {
    2  console.log("111111111")
    3 }
    4 
    5 const result = test();
    6 console.log(result);

    浏览器打印结果如下:
    ‘111111111’
    Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
    也就是说结果返回的是Promise.resolve(undefined)

    看到这里明白了吗?async 函数返回的是一个 Promise 对象。也就是说如果我们在async函数中 return 一个常量,async 会把这个常量通过 Promise.resolve() 封装成 Promise 对象。

    既然是 Promise 对象,那我们也就可以通过then()方法获取其值,如下

    test().then(res => {
        console.log(res);    // 输出 hello world
    });

    看了上面的代码,是不是很不明白async/await到底有啥用?

    我们知道Promise 的特点——无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。

    那么下一个关键点就在于 await 关键字了。

    4、await 有啥用,做了什么?

    await 操作符一般说来是用于等待一个Promise 对象。它只能在异步函数 async function 中使用。但事实是,await后可以是一个 Promise 对象或者任何要等待的值。请参见:await 语法

    如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果

    function test(x) {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(x);
        }, 2000);
      });
    }
    
    async function f1() {
      var x = await test(10);
      console.log(x); // 10
    }
    f1();

    如果该值不是一个 Promise,await 会把该值转换为已正常处理的Promise,然后等待其处理结果。

    async function f2() {
      var y = await 20;
      console.log(y); // 20
    }
    f2();

    如果 Promise 处理异常,则异常值被抛出。

    async function f3() {
      try {
        var z = await Promise.reject(30);
      } catch (e) {
        console.log(e); // 30
      }
    }
    f3();

    5、async/await 的优势在于处理 then 链

    这个是使用async/await最优势的地方

    单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了(其实,Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它,也可以说是async/await基于Promise 做了更好的处理)

    假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:

    下边这几段代码是复制网上的案例,能够说明问题就行。
    /**
     * 传入参数 n,表示这个函数执行的时间(毫秒)
     * 执行的结果是 n + 200,这个值将用于下一步骤
     */
    function takeLongTime(n) {
        return new Promise(resolve => {
            setTimeout(() => resolve(n + 200), n);
        });
    }
    
    function step1(n) {
        console.log(`step1 with ${n}`);
        return takeLongTime(n);
    }
    
    function step2(n) {
        console.log(`step2 with ${n}`);
        return takeLongTime(n);
    }
    
    function step3(n) {
        console.log(`step3 with ${n}`);
        return takeLongTime(n);
    }

    现在用 Promise 方式来实现这三个步骤的处理

    function doIt() {
        console.time("doIt");
        const time1 = 300;
        step1(time1)
            .then(time2 => step2(time2))
            .then(time3 => step3(time3))
            .then(result => {
                console.log(`result is ${result}`);
                console.timeEnd("doIt");
            });
    }
    
    doIt();
    
    // c:var	est>node --harmony_async_await .
    // step1 with 300
    // step2 with 500
    // step3 with 700
    // result is 900
    // doIt: 1507.251ms

    输出结果 result 是 step3() 的参数 700 + 200 = 900。doIt() 顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果一致。

    如果用 async/await 来实现呢,会是这样

    async function doIt() {
        console.time("doIt");
        const time1 = 300;
        const time2 = await step1(time1);
        const time3 = await step2(time2);
        const result = await step3(time3);
        console.log(`result is ${result}`);
        console.timeEnd("doIt");
    }
    
    doIt();

    结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样。

    关于async/await 处理 then 链,网上有很多文章,可以搜搜,基本可以理解的差不多。

    总结参考文章:https://www.jianshu.com/p/5cae46133bad

    function takeLongTime(n) {
        return new Promise(resolve => {
            setTimeout(() => resolve(n + 200), n);
        });
    }

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

    万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!

  • 相关阅读:
    [组合数取模] 方法汇总
    机房收费系统(VB.NET)——存储过程实战
    Remove Duplicates from Sorted Array
    Android ListFragment实例Demo(自己定义适配器)
    混合模式程序集是针对“v1.1.4322”版的执行时生成的,在没有配置其它信息的情况下,无法在 4.0 执行时中载入该程序集。
    小编接地气——第六届中国云计算大会攻略Q&A
    有统计的百度分享
    Yii CGridView 基本使用(三)关联表相关字段搜索
    扯谈网络编程之Tcp SYN flood洪水攻击
    多平台响应键盘事件!(适用于Cocos2dx 3.0 alpha以上版本号)
  • 原文地址:https://www.cnblogs.com/mahmud/p/11518475.html
Copyright © 2011-2022 走看看