JavaScript中的非同步/等待(async/await)

JavaScript中的非同步/等待(async/await)

在本文中,我們將解釋JavaScript中的非同步/等待(async/await)。

YouTube Video

JavaScript中的非同步/等待(async/await)

JavaScript中的async(和await)是為了讓編寫非同步操作更加直觀且易讀而設計的功能。通過使用這個,可以減少傳統回呼函式和 Promise 鏈的複雜性,並且可以用類似同步程式碼的方式來撰寫非同步程式碼。

async函式

async用於將一個函式定義為非同步函式。一個async函式總是返回一個Promise。在標記為async的函式內,你可以使用await等待Promise的結果返回。

async函式的基本語法

1async function myAsyncFunction() {
2    // Write asynchronous processing here
3    return 'Result';  // Return a Promise
4}

在這種情況下,呼叫myAsyncFunction()會自動返回一個Promise對象。當Promise被解析時,其結果成為return所返回的值。

範例:基本async函式

1async function greet() {
2    return 'Hello, World!';
3}
4
5greet().then((message) => {
6    console.log(message);  // Displays "Hello, World!"
7});

await

await用於等待Promise被解析。通過使用await,你可以暫停執行,直到Promise被解析並獲得Promise的結果。await只能在async函式內使用。

範例:如何使用await

 1async function fetchData() {
 2    // Wait for the result of the Promise
 3    const data = await fetch('https://codesparklab.com/json/example.json');
 4    // Wait for the asynchronous operation to complete
 5    const jsonData = await data.json();
 6    // Retrieve and display the data
 7    console.log(jsonData);
 8}
 9
10fetchData();

在上述範例中,透過await等待fetch函式返回的Promise,隨後使用結果進行進一步的非同步操作。

使用async/await進行錯誤處理

如果在async函式內發生錯誤,該錯誤會被視為Promise的reject。你可以使用try...catch語句來進行錯誤處理。

範例:錯誤處理

 1async function fetchData() {
 2    try {
 3        // Invalid URL
 4        const data = await fetch('https://invalid.codesparklab.com/');
 5        const jsonData = await data.json();
 6        console.log(jsonData);
 7    } catch (error) {
 8        // Catch the error
 9        console.error('Failed to fetch data:', error);
10    }
11}
12
13fetchData();

使用try...catch區塊可以捕獲非同步操作中發生的錯誤,避免程式在錯誤發生時崩潰。

async/await的優點

與傳統的 Promise 鏈相比,async/await 具有以下優點:。

  • 可讀性提升
    • 非同步處理可以像同步程式碼一樣書寫,避免了深層嵌套的 Promise 鏈和回呼的複雜性。
  • 更易於偵錯
    • 由於程式碼類似同步程式碼,偵錯及錯誤處理變得更容易。
  • 更高的維護性
    • 非同步處理可以更簡單地書寫,使修改或更換程式碼更容易,提高了長期的可維護性。

範例:Promise 鏈 vs async/await

讓我們比較使用 Promise 鏈的程式碼與使用 async/await 的程式碼。

 1// Code using Promise chains
 2function fetchDataPromise() {
 3    fetch('https://codesparklab.com/json/example.json')
 4        .then((response) => response.json())
 5        .then((data) => {
 6            console.log(data);
 7        })
 8    .catch((error) => {
 9        console.error('Failed to fetch data:', error);
10    });
11}
12
13// Code using async/await
14async function fetchDataAsync() {
15    try {
16        const response = await fetch('https://codesparklab.com/json/example.json');
17        const data = await response.json();
18        console.log(data);
19    } catch (error) {
20        console.error('Failed to fetch data:', error);
21    }
22}

如你所見,使用 async/await 可讓你以直線式方式撰寫非同步處理,使程式碼更加易讀。

同時執行多個非同步操作

通過將 Promise.all()Promise.race()await 結合使用,可以同時執行多個非同步操作並集體處理其結果。

Promise.all()

 1async function fetchMultipleData() {
 2    try {
 3        const [data1, data2] = await Promise.all([
 4            fetch('https://codesparklab.com/json/example1.json'),
 5            fetch('https://codesparklab.com/json/example2.json')
 6        ]);
 7        const jsonData1 = await data1.json();
 8        const jsonData2 = await data2.json();
 9        console.log(jsonData1);
10        console.log(jsonData2);
11    } catch (error) {
12        console.error('Failed to fetch data:', error);
13    }
14}
15
16fetchMultipleData();
  • Promise.all() 同時解析多個 Promise,並以數組形式返回它們的結果。它會等待所有的 Promise 被解析,如果其中任何一個失敗,則整體視為失敗。

Promise.race()

 1async function fetchFastestData() {
 2    try {
 3        const fastestResponse = await Promise.race([
 4            fetch('https://codesparklab.com/json/example1.json'),
 5            fetch('https://codesparklab.com/json/example2.json')
 6        ]);
 7        const jsonData = await fastestResponse.json();
 8        console.log('Fastest data:', jsonData);
 9    } catch (error) {
10        console.error('Fetch error:', error);
11    }
12}
13
14fetchFastestData();
  • Promise.race() 會返回第一個完成(無論成功或失敗)的 Promise 的結果。當你想對最先完成的非同步操作做出回應時,這會非常有用。然而,如果第一個 Promise 失敗,錯誤會立刻被 catch 捕捉到。

Promise.allSettled()

 1async function fetchWithAllSettled() {
 2    const results = await Promise.allSettled([
 3        // This URL will success
 4        fetch('https://codesparklab.com/json/example1.json'),
 5        // This URL will fail
 6        fetch('https://invalid.codesparklab.com/')
 7    ]);
 8
 9    results.forEach((result, index) => {
10        if (result.status === 'fulfilled') {
11            const url = result.value.url;
12            console.log(`Request ${index + 1} succeeded:`, url);
13        } else {
14            const reason = result.reason;
15            console.warn(`Request ${index + 1} failed:`, reason);
16        }
17    });
18}
19
20fetchWithAllSettled();
  • Promise.allSettled() 會等待所有的結果,不論是成功還是失敗。每個結果會以 { status, value }{ status, reason } 的形式返回,使你可以判斷哪些 Promise 成功、哪些失敗。

Promise.any()

 1async function fetchAnySuccessful() {
 2    try {
 3        const firstSuccessful = await Promise.any([
 4            // This URL will fail
 5            fetch('https://invalid.codesparklab.com/'),
 6            // This URL will success
 7            fetch('https://codesparklab.com/json/example1.json')
 8        ]);
 9        const jsonData = await firstSuccessful.json();
10        console.log('First successful response:', jsonData);
11    } catch (error) {
12        console.error('All fetch requests failed:', error);
13    }
14}
15
16fetchAnySuccessful();
  • Promise.any() 只會返回第一個成功完成的 Promise 的結果。只有當所有的 Promises 都失敗時,才會拋出異常。在某些 API 不太穩定的情況下,它可以作為重試機制使用,直到其中一個成功為止。

總結

  • async 函數:總是返回一個 Promise,用於編寫非同步處理。
  • await:用於等待 Promise 被解析並接收其結果。
  • 錯誤處理:使用 try...catch 處理非同步處理過程中出現的錯誤。
  • 多個非同步操作:透過使用像是 Promise.all() 這樣的方法,你可以同時執行多個非同步任務。

async/await 是處理非同步處理的強大工具,務必善用它們以簡化複雜的非同步邏輯。

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video