异步操作要了解的ES7的async/await

Posted mahmud

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步操作要了解的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\test>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);
    );

以上是关于异步操作要了解的ES7的async/await的主要内容,如果未能解决你的问题,请参考以下文章

理解ES7中的async/await

es7 async await 异步

ES7的Async/Await的简单理解

vue中使用async/await的实践

ES7 - 如何停止(剪切)异步/等待链接

关于ES7里面的async和await