JavaScript学习日记 : Day17 - Async Await

上一篇介绍到Promise可以用来处理非同步行为,但始终在阅读性方面还是不是很优,今天要介绍的是基於Promise让非同步的语法结构类似同步语言 --- Async/await,还有一些额外的优点也会一并介绍。

1. Async

在一个函数前面加async可以确保此函数返回的是promise,其他返回的值都会被包装成resolve:

async function test() {
    return 10
}

test().then( res => console.log(res)) // 10

直接返回promise也是可以的:

async function test() {
    return Promise.resolve(1)
}

test().then( res => console.log(res))  //1

2. Await

首先await只能在async函数中运作,所以基本上async/await是一体的,不会单独出现,await会让JavaScript引擎等到promise完成(settle)且返回结果:

async function test() {
    let result = await new Promise((resolve, reject) => {
        setTimeout(() => resolve("成功!"),1000)
    })
    
    console.log(result);
}

test(); // 一秒後 "成功"

续用昨天文章中的函数来说明:

function ownPromise(count, time = 1000) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            count? resolve(`第${count}次成功!`) : reject("失败")
        },time)
    })
}

我们可以得到以下结论:

  1. async用来定义非同步函数
  2. await可以确保特定的promise settle後才继续往下执行
console.log("Start")

async function fetchData() {
    const dataA = await ownPromise(1);
    const dataB = await ownPromise(2);
    console.log(dataA, dataB)
}

fetchData();

console.log("End!")

// 

Start!
End!

第1次成功! 第2次成功!

其中fetchData其实一样是非同步的部分,但是透过await可以做到让async function内的非同步是以同步的方式依序执行。

3. Error handle

我们一样用ownPromise来说明,promise可以透过chain的方式来做error handle,且一旦遇到错误会直接跳转到catch:

ownPromise(0).then( res => {
    console.log(res);
    return ownPromise(1);
}).then( res => {
    console.log(res);
    return ownPromise(2);
}).catch( err => {
    console.log(err);
})

// 失败  ownPromise(0)失败直接跳转到catch

那async/await因为已经转为同步的形式,所以如果遇到error没有处理的话,後续的代码都没办法运行,async/await的error handle一样用try..catch来处理:

async function fetchData() {
    try {
        const dataA = await ownPromise(1);
        const dataB = await ownPromise(0);
        console.log(dataA, dataB)
    } catch(err) {
        console.log('catch error',err)
    }
    
}

fetchData();

4. Async/await其他技巧

async/await因为让非同步变成同步的形式,所以可以跟JavaScript语法一起搭配使用。

4.1 for...loop(依序发出request)

for..loop会等到当前的回圈中的await有回应後,且执行完回圈所有代码後才会进入下一个回圈,所以非常适合用来依序发出request。

let arrayData = [
    {count:1, time:1000},
    {count:2, time:2000},
    {count:3, time:3000},
    {count:4, time:4000},
]

// 情况一
async function testForLoop() {
    const resArray = [];
    
    for(let i = 0; i < arrayData.length; i++) {
        const item = arrayData[i]
        resArray.push(ownPromise(item.count, item.time));
        console.log(`${item.count}执行完毕`)
    }
    
    console.log(resArray)
}

testForLoop();

// 情况二

async function testForLoop() {
    const resArray = [];
    
    for(let i = 0; i < arrayData.length; i++) {
        const item = arrayData[i]
        resArray.push(await ownPromise(item.count, item.time));
        console.log(`${item.count}执行完毕`)
    }
    
    console.log(resArray)
}

testForLoop();

4.2 forEach(同时发出request)

forEach的概念是每个item依序执行callback function,但是一旦开始执行後就马上接着换下一个item,所以会几乎同时执行每个回圈内容。

let arrayData = [
    {count:1, time:1000},
    {count:2, time:2000},
    {count:3, time:3000},
    {count:4, time:4000},
]

// 情况一
async function testForEach() {
    const resArray = [];
    
    arrayData.forEach(item => {
        resArray.push(ownPromise(item.count, item.time))
        console.log(`第${item.count}次执行完毕!`)
    })
    
    console.log(resArray);
    
    for(const res of resArray) {
        console.log(await res)
    }
    
}

testForEach();

// 情况二
async function testForEach() {
    const resArray = [];
    
    arrayData.forEach(async item => {
        resArray.push(await ownPromise(item.count, item.time))
        console.log(`第${item.count}次执行完毕!`)
    })
    
    console.log(resArray);
}

testForEach();

4.3 Map(同时发出request)

与forEach类似,也是几乎同时执行,但是会马上执行return的动作,会无视async/await直接return。

let arrayData = [
    {count:1, time:1000},
    {count:2, time:2000},
    {count:3, time:3000},
    {count:4, time:4000},
]

// 情况一
async function testMap() {
    let resArray = arrayData.map(item => {
        return ownPromise(item.count, item.time)
    })
    
    console.log(resArray);
    
    for(const res of resArray) {
        console.log(await res)
    }
}

testMap();

// 情况二

async function testMap() {
    let resArray = arrayData.map(async item => {
        return await ownPromise(item.count, item.time)
    })
    
    console.log(resArray);
    
    for(const res of resArray) {
        console.log(await res)
    }
}

testMap();

所以情况一与二的结果是一样的:


<<:  Day16:【技术篇】SQL之基本CRUD处理能力

>>:  浅谈传输层协定(一):TCP 在做什麽?

Day 06:Debug

前言 为什麽要把 debug 拿出来说呢? 我发现其实 debug 的流程比较少人讨论, 一般我们会...

Use Cisco CCIE 350-701 Dumps For Instant Success

Use Actual Cisco 350-701 Dumps to Learn Faster Pas...

第0砍 - 虚张声势

: 听说你ARM很厉害 你怎麽学习的? 学习? 每天伏地挺身100下就好了阿 : ??? 在进入正题...

新零售行销模式案例,全通路时代来临该如何布局

新零售行销模式案例,全通路时代来临该如何布局,一直以来都在担任辅导顾问为中小企业解决网路行销问题但都...

DAY 1 系列文章启文

近年来 ROS (Robot Operating System,机器人作业系统) 目前已成熟应用於智...