iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Modern Web

JavaScript學習日記系列 第 17

JavaScript學習日記 : Day17 - Async Await

  • 分享至 

  • xImage
  •  

上一篇介紹到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();

所以情況一與二的結果是一樣的:


上一篇
JavaScript學習日記 : Day16 - Promise
下一篇
JavaScript學習日記 : Day18 - Class
系列文
JavaScript學習日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言