Skip to content

async/await

async/await 是 JavaScript 中用來處理異步操作的語法糖,基於 Promise,讓異步程式碼看起來更像同步程式碼。這使得代碼更易讀、更易於理解,特別是在處理複雜的異步邏輯時。下面將詳細說明 async/await 的使用方式,包括基礎語法、錯誤處理、在迴圈中的使用,以及與 Promise 的結合。

1. 基本語法

1.1 async 關鍵字

async 關鍵字用於定義一個異步函式。異步函式會自動將返回值包裝在一個 Promise 物件中。

async function exampleFunction() {
    return "Hello, world!";
}

exampleFunction().then(result => console.log(result));  // 輸出 "Hello, world!"

即使直接返回一個值,async 函式也會返回一個已完成狀態的 Promise

1.2 await 關鍵字

await 關鍵字只能在 async 函式內部使用,用來等待一個 Promise 完成。當 await 等待的 Promise 完成後,會返回該 Promise 的結果。如果 Promise 被拒絕(rejected),await 會拋出異常。

async function fetchData() {
    let response = await fetch('https://api.example.com/data');
    let data = await response.json();
    console.log(data);
}

fetchData();
在這個範例中,await 暫停函式的執行,直到 fetchPromise 完成並返回結果。這使得 fetchData 函式內的代碼看起來像同步的。

2. 錯誤處理

async/await 允許你使用傳統的 try...catch 結構來捕獲異步操作中的錯誤,這比 Promisecatch 方法更加直觀。

async function fetchData() {
    try {
        let response = await fetch('https://api.example.com/data');
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Fetch error:', error);
    }
}

fetchData();
在這個例子中,try 區塊中的代碼嘗試執行,如果 await 等待的 Promise 被拒絕或拋出異常,catch 區塊會捕獲並處理錯誤。

3. 在迴圈中使用 async/await

當需要對多個異步操作依次執行時,async/await 可以與迴圈結合使用。這樣可以確保每個異步操作在前一個操作完成後才開始執行。

async function fetchMultipleUrls(urls) {
    for (let url of urls) {
        let response = await fetch(url);
        let data = await response.json();
        console.log(data);
    }
}

let urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
fetchMultipleUrls(urls);

這個例子中,每個 fetch 操作會等待前一個操作完成後再開始,這保證了按順序處理每個請求。

4. 並行執行異步操作

儘管 await 使代碼看起來像是同步執行,但有時你可能希望並行執行多個異步操作,而不是一個接一個地執行。你可以結合 Promise.allasync/await 來達成這一目的。

async function fetchMultipleUrls(urls) {
    let fetchPromises = urls.map(url => fetch(url));
    let responses = await Promise.all(fetchPromises);
    let dataPromises = responses.map(response => response.json());
    let allData = await Promise.all(dataPromises);
    console.log(allData);
}

let urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
fetchMultipleUrls(urls);

在這個範例中,所有的 fetch 請求會並行執行,然後等待所有請求完成後,再處理每個回應。

5. 與傳統 Promise 的比較

雖然 async/await 是基於 Promise 的,但它提供了更簡潔的語法,讓異步代碼更加可讀。

傳統的 Promise 語法:

fetch('https://api.example.com/data')
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
    .then(data => console.log(data))
    .catch(error => console.error('Fetch error:', error));

使用 async/await 的語法:

async function fetchData() {
    try {
        let response = await fetch('https://api.example.com/data');
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Fetch error:', error);
    }
}

fetchData();
在這裡,async/await 讓異步代碼看起來更像是線性、同步的代碼,而不是嵌套的回調函式。

6. 與同步代碼的結合

雖然 async/await 用於異步操作,但你仍然可以將同步代碼與其結合。await 只會影響到它所等待的 Promise,其他同步代碼不會受到影響。

async function exampleFunction() {
    console.log("Start");

    let promise = new Promise((resolve) => setTimeout(resolve, 2000));
    await promise;

    console.log("End after 2 seconds");
}

exampleFunction();
在這個範例中,"Start" 會立即被輸出,而 "End after 2 seconds" 會在 2 秒後輸出,這展示了 async/await 與同步代碼的結合。

總結

async/await 是處理 JavaScript 異步操作的強大工具。它建立在 Promise 的基礎上,提供了更簡潔、更直觀的方式來編寫和管理異步代碼。無論是在處理簡單的 API 請求,還是管理複雜的異步邏輯,async/await 都能讓你的代碼更加清晰和易於維護。