iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0
自我挑戰組

登堂入室!前端工程師的觀念技術 _30_ 題系列 第 13

12. 使用 async & await (Fetch API)

【9.14補充內容】增加了fetch API的應用,然後修改了一些async & await的範例。

async & await


async & await是一個基於promise的語法糖。

運作原理和promise一模一樣,主要包含兩個部分:

  • async : async function 宣告一個非同步函式,可以告訴function在最後回傳一個promise
  • await : await必須放在任何基於promise的函數之前,等到獲得resolve的資料後,再執行後續動作
    (await放在async function裡才有作用。)

示例

假設原來的程式碼長這樣:

function greeting() { 
  return new Promise( (resolve,reject) => {
    resolve("Hello"); 
});
}

greeting()
  .then((value) => console.log(value));
  
// output: "Hello"

【async】

我們先嘗試使用async:

async function greeting() { return "Hello" };

greeting()
  .then((value) => console.log(value));

// output: "Hello"

因為非同步函式greeting()回傳的會是一個promise,所以可以省略建構promisenew Promise

【await】

而await必須放在任何基於promise的函數之前,
改寫new Promise建構式的寫法:

async function greeting(){
    let example = await new Promise( (resolve,reject) => {
    resolve("Hello"); 
});
return example;
}

greeting()
  .then((value) => console.log(value));
// output: "Hello"

await的作用是,
在得到resolve的物件後,才執行let example的給值。

【Promise.resolve()】

更簡便的寫法,可以使用Promise.resolve()函式:

async function greeting(){
    let example = await Promise.resolve("Hello");
    return example;
}

greeting()
  .then((value) => console.log(value));
// output: "Hello"

我們可以用Promise.resolve()這個方法回傳一個 指定resolve值的promise,
這裡的重點是 一樣要加上await。

【Promise.reject()】

async function greeting(){
    let example = await Promise.reject("Error"); 
    return example;
}

greeting()
  .then((value) => console.log(value))
  .catch((error) => console.log(error))

// output: "Error"

我們可以用Promise.reject()這個方法,則回傳一個reject的promise,
一樣可以用catch來獲得錯誤訊息。

【try & catch】

async & await 也可以搭配另一種處理錯誤訊息的方法,也就是 try & catch

繼續改寫上面的例子:

async function greeting(){
  try {
    let example = await Promise.resolve("Hello"); 
    console.log(example);
  } catch (error) {
    console.log(error);
  }
}

greeting();

// output: "Hello"

try負責正常獲得資料的處理,catch 則能直接獲取錯誤訊息。

好了!學到這裡可以嘗試接外部的API的,
但今天不用XHR(XMLHttpRequest),改用另一種更現代的方式。

Fetch API


API(Application Programming Interface)可以視為一種的工具,用於讓開發者便於請求資料。

Fetch API 提供了 fetch() 方法,fetch() 會回傳一個不論請求成功或失敗,都是 resolve 的 promise。

示例

fetch() 的參數必須為請求資料的網址。

首先可以嘗試使用 Fetch 發送請求 ( request ),這裡我們使用 {JSON} Placeholder 作為例子。
( 可以參考 JSONPlaceholder - Free Fake REST API)

const request = 'https://jsonplaceholder.typicode.com/todos/1';

// fetch 會依照 request 去取得資料
fetch(request)
  .then(response => response.json()) // json()會解析回傳的Response物件
  .then(json => console.log(json)) 

執行步驟

  1. fetch() : 會依照參數裡指定的url去取得資料,且會直接resolve回傳的Promise,這個Promise 會包含 Response物件。
  2. .json() : fetch()回傳的Promise( Body text )還要需要經過解析,.json()是其中一種。
    .json()會把fetch回來的Promise解析成JSON型別Promise。

The fetch() method...
It returns a Promise that resolves to the Response to that request — as soon as the server responds with headers — even if the server response is an HTTP error status.

這樣會回傳URL裡todos/裡的第一筆資料。

// output:
{
	"userId": 1,
	"id": 1,
	"title": "delectus aut autem",
	"completed": false
}

Everything together!!

那來嘗試把資料改寫成async await吧!
原本的程式碼:

let requestURL = 'https://jsonplaceholder.typicode.com/todos/1';

fetch(requestURL)
    .then((response) => {
        return response.json();
    })
    .then((data) => {
        console.log(`Title: ${data.title}`);
        if (data.completed !== true){
          console.log("Undo");
        } else {
          console.log("Done!!");
        }
    })
    .catch((error) => {
        console.log(`Error: ${error}`);
    })

/* output:
    "Title: delectus aut autem"
    "Undo"
*/

改寫: 使用 async&await,並利用 try&catch 處理錯誤訊息。

let requestURL = 'https://jsonplaceholder.typicode.com/todos/1';

async function getTodoList(url){
  try {
    let response = await fetch(url);
    let data = await response.json();
    console.log(`Title: ${data.title}`);
    if (data.completed !== true){
      console.log("Undo");
    } else {
      console.log("Done!!");
    }
  } catch(error) {
    cconsole.log(`Error: ${error}`);
  }
}

getTodoList(requestURL);

fetch相較於XHR更強大且更有彈性(意思應該是fetch有很多功能),MDN提供了很多使用方式和範例,可以參考這個頁面: Using Fetch - Web APIs | MDN

結論

一樣放上一些相關的問題:

  • Promise 和 async await 要解決的是什麼問題?
    解決舊語法產生callback hell的問題,避免呼叫太多callback時,程式碼難以判讀且後續難以維護。
    (這題其實是考callback hell,詳細可以看舊文章,因為今天才複習async await所以放在這。)

【如內文有誤還請不吝指教>< 謝謝閱覽至此的各位:D】

參考資料:


上一篇
11. 解釋 Callback Hell & 使用Promise
下一篇
13. 關於 IIFE 的 4 題練習
系列文
登堂入室!前端工程師的觀念技術 _30_ 題31

尚未有邦友留言

立即登入留言