# 异步神器async-await

# 前言

前后端分离的今天,前端api请求很多都是异步的,然后多个api可能需要有先后顺序。ES5解决办法是回调,但是回调会陷入回调地狱。ES6的解决办法是Promise,但是书写会横向发展,无数多个.then().ES7的解决办法async-await,今天是我们的主角

# 回调,Promise,async-await 列子和关系

async-await是promise和generator的语法糖。只是为了让我们书写代码时更加流畅,同时增加了代码的可读性。

# 回调举例

es5中的回调函数指的是一个函数作为参数传递到另外一个函数中

// 多次调用函数并嵌套
function sleep(call){
  setTimeout(function(){
    call()
  },1000)
}
//循环调用--每隔一秒调用一次sleep打印出结果
sleep(function(){
  console.log(111)
  sleep(function(){
    console.log(222)
  })
1
2
3
4
5
6
7
8
9
10
11
12

弊端:回调的越多,嵌套的越多,会陷入回调地狱

# promise举例

Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码;让代码更加的直观。就是当执行完一次异步操作后,会有一次回调,不管成功还是失败,成功就对应成功的回调,失败就对应失败的回调。

Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('111')
            resolve(' enough sleep~');
        }, second);
    })
}
sleep(2).then(() => {
    console.log('222')
})
Promise {<pending>}
VM274:4 111
VM379:2 222
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# async 和 await

async-await是promise和generator的语法糖

# async

async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数

async ƒ demo01() {
    return 123;
}

async function demo01() {
    return 123;
}

demo01().then(val => {
    console.log(val);
})
VM597:2 123

若 async 定义的函数有返回值,return 123;相当于Promise.resolve(123),没有声明式的 return则相当于执行了Promise.resolve();
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# await

await可以理解为是async wait的简写

await 后面可以跟任何的JS 表达式。虽然说 await 可以等很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。如果await的是 promise对象会造成异步函数停止执行并且等待 promise 的解决,如果等的是正常的表达式则立即执行。

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(' enough sleep~');
        }, second);
    })
}
function normalFunc() {
    console.log('normalFunc');
}
async function awaitDemo() {
    await normalFunc();
    console.log('something, ~~');
    let result = await sleep(2000);
    console.log(result);// 两秒之后会被打印出来
}
awaitDemo();

VM391:9 normalFunc
VM391:13 something, ~~
Promise {<pending>}__proto__: Promise[[PromiseState]]: "fulfilled"[[PromiseResult]]: undefined
VM391:15  enough sleep~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 示例

举例说明啊,你有三个请求需要发生,第三个请求是依赖于第二个请求的解构第二个请求依赖于第一个请求的结果。若用 ES5实现会有3层的回调,若用Promise 实现至少需要3个then。结果就是一个代码横向发展,另外一个是纵向发展

//我们仍然使用 setTimeout 来模拟异步请求
function sleep(second, param) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(param);
        }, second);
    })
}

async function test() {
    let result1 = await sleep(2000, 'req01');
    let result2 = await sleep(1000, 'req02' + result1);
    let result3 = await sleep(500, 'req03' + result2);
    console.log(`
        ${result3}
        ${result2}
        ${result1}
    `);
}

test();
//req03req02req01
//req02req01
//req01
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 错误处理演示

为了处理Promise.reject 的情况我们应该将代码块用 try catch 包裹一下

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('want to sleep~');
        }, second);
    })
}

async function errorDemo() {
    let result = await sleep(1000);
    console.log(result);
}
errorDemo();// VM706:11 Uncaught (in promise) want to sleep~

// 为了处理Promise.reject 的情况我们应该将代码块用 try catch 包裹一下
async function errorDemoSuper() {
    try {
        let result = await sleep(1000);
        console.log(result);
    } catch (err) {
        console.log(err);
    }
}

errorDemoSuper();// want to sleep~
// 有了 try catch 之后我们就能够拿到 Promise.reject 回来的数据了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 多个请求并行处理

还是需要用到promise(Promise.all()),这里async-await就不适用了

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('request done! ' + Math.random());
        }, second);
    })
}

async function correctDemo() {
    let p1 = sleep(1000);
    let p2 = sleep(1000);
    let p3 = sleep(1000);
    await Promise.all([p1, p2, p3]);
    console.log('clear the loading~');
}
correctDemo();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 注意点

1.for循环中可以用到await,但是forEach中不能

# 资料

1.ES6系列文章 异步神器async-await (opens new window)

全量分析

评 论:

上次更新时间: 6/24/2021, 2:57:17 PM