Node-JS专精11_03async_await

async / await

常用用法

1
2
3
4
5
6
7
8
const fn = async () => {
// makePromise 返回 promise的函数
const temp = await makePromise()
return temp + 1;
}

// 这个 makePromise 如果成功了就会返回一个值
// 如果失败了,就会报错,你就必须用 try / catch 才能拿到那个值,但是也不一定后面会说

优点

  • 完全没有缩进,就像是写同步代码

封装一个 async 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function 摇骰子(){
return Math.floor(Math.random()*6)+1
}

// 如果需要 reject , 直接 throw Error('xxx')

// 使用

async function fn(){
const result = await 摇骰子();
console.log(result)
}

// 如果需要处理错误,可以 try catch

fn(); // 直接打印摇骰子结果

但是如果想要 3秒后得到摇骰子的结果 就就没法直接写,必须有一个 Promise

实现3秒后摇骰子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function 摇骰子3秒后(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(Math.floor(Math.random()*6)+1)
},3000)
})
}

async function fn2(){
const result = await 摇骰子3秒后();
console.log(result)
}

fn2()

抛出错误 / 解惑错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
async function 摇骰子(){
throw new Error('骰子坏了')
}

async function fn(){
try {
var result = await 摇骰子()
console.log(result);
} catch(e){
console.log(e)
}
}

fn();

为什么需要 async

  • await 所在的函数不就是 async 函数吗? 但是为什么还是要加上 async声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function 摇骰子(){
throw new Error('骰子坏了')
}
// 删掉 async
function fn(){
try {
var result = await 摇骰子()
console.log(result);
} catch(e){
console.log(e)
}
}

fn()
  • 原因是在 await出现之前,有些人自己写了 await
1
2
3
4
// 旧代码,自己实现的 await
function fn(){
var res = await(摇骰子())
}

为什么加了 async

  • 由于那些自己实现 await 的人来说 ,如果 await 不配合 async 直接发布它的代码就不能用,不兼容
  • 如何兼容呢? 于是JS设计者想到的是 在外面包一层 来加以区别
  • 最终原因只有一个:兼容旧代码里,普通函数里的 await(xxx) 所以在所有出现 await 的地方外面加了一个 async

await的错误处理

常见方式

  • 一个字:丑
1
2
3
4
5
6
7
8
function fn(){
try {
var result = await axios.get('/xxx')
console.log(result);
} catch(e){
console.log(e)
}
}

正确姿势

  • then 和 await 结合使用,在 then 里处理异步错误, await只接受成功的结果
  • 能处理90%的情况
1
2
3
const result = await axios.get('/xxx').then(null,errorHandler)
console.log(result)
// 错误处理放在 then里面

细节

  • 可以把 4xx/5xx等常见错误用拦截器全局处理
  • await只关心成功,失败全部交给 errorHandler
  • errorHandler 也可以放在拦截器里

示例代码

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
27
ajax = function(){
return new Promise((resolve,reject)=>{
/*
// 成功处理
resolve({
data:{name:'a'}
})
*/
reject({
response:{status:403}
})
})
}

var error = (e)=>{
console.log(e)
console.log('提示用户没有权限')
throw e
}

async function fn(){
const response = await ajax().then(null,error)
console.log(response)
}


fn()

await 的传染性

1
2
3
4
5
console.log(1)
await console.log(2)
console.log(3)

导致 3 要等一会才被打印,因为有 await, 导致它下面的代码变成异步任务

分析

1
2
3
console.log(3) 变成异步任务了
Promise 同样具有传染性 (同步变异步)
谁没有传染性 : 回调

await 应用场景

多次处理一个结果

1
2
3
const s1 = await makePromise();
const s2 = handlerR1(r1)
const s3 = handlerR2(r2)

串行

  • 天生串行

    1
    2
    3
    4
    5
    6
    7
    async function fn(){
    await ajax1();
    await ajax2();
    await ajax3();
    await ajax4();
    await ajax5();
    }
  • 循环的时候有 bug

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 实际上它是并行的
    async function fn(){
    var array = [ajax1, ajax2, ajax3]
    for(let i=0;i<array.length;i++){
    await array[i]
    }
    }

    /*
    跟你直接这样 不一样
    await ajax1();
    await ajax2();
    await ajax3();
    */

    // 用 await 循环
    搜索关键字 for-await-of

并行

  • await Promise.all() 就是并行了