你需要了解的ES7的async/await

简介: 你需要了解的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。

我们先看个例子:

var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve();
        }, time);
    })
};
var start = async function () {
    // 在这里使用起来就像同步代码那样直观
    console.log('start');
    await sleep(3000);
    console.log('end');
};
start();

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

2、我们需要知道的是:

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

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

async function test() {
  return "hello world";
}
const result = test();
console.log(result);

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

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

async function test() {
 console.log("111111111")
}
const result = test();
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 链,网上有很多文章,可以搜搜,基本可以理解的差不多。


相关文章
|
2月前
|
前端开发 JavaScript
什么是 async、await ?
什么是 async、await ?
|
5月前
|
JSON 前端开发 JavaScript
async/await的应用
async/await的应用
30 0
|
7月前
|
前端开发 JavaScript
|
20天前
|
前端开发 JavaScript
async/await
async/await
16 0
|
1天前
|
前端开发
async、await
async、await
|
3月前
|
前端开发 JavaScript
|
4月前
|
前端开发
ES7 async await return value
ES7 async await return value
|
8月前
|
前端开发 API
Async/Await 在何时该使用,何时不使用
使用 async/await 是在处理异步操作时的一种更简洁、易读的方式,它基于 Promise,并且可以使异步代码看起来像同步代码一样编写。然而,并不是所有情况下都需要使用 async/await。
104 0
|
消息中间件 前端开发 JavaScript
ES8 中的 async/await —— 异步函数
ES8 中的 async/await —— 异步函数
150 0