API 串接是前端很重要的技術,但是這篇不是來解釋什麼是 API (想知道的看這裡),而是記錄當前比較常用來串接 API 的四種方法:Ajax、jQuery Ajax、Fetch API 和 Axios 的基礎用法。
這篇文章要串接 RANDOM USER GENERATOR 這個 API 來簡單做個可互動的網頁:在點擊按鈕後就隨機跑出一筆使用者資料。
這是 ALPHA Camp 學期 2-2 的作業,但作業是用 Axios 串的,所以這次我要使用其他三種方法串串看。先上個成果圖:
在開始之前,先把前置作業做好:
// HTML
<div class="container">
<button id='find'>Random User</button>
<div id='show'></div>
</div>
// JavaScript
const find = document.querySelector("#find")
const show = document.querySelector("#show")
let apiUrl = 'https://randomuser.me/api/'
let name = ''
let img = ''
let email = ''
然後建議先去 RANDOM USER GENERATOR 看看,它會有一些解說該怎麼串接,然後串接完成會獲得什麼資料。
全名 Asynchronous JavaScript and XML,是最早最早串接 API 的方法,而 Ajax 的出現開始讓網頁實現非同步請求,可以說現在的 API 串接方法都奠基在 Ajax 上。但它也因為是最老的,所以相對也是最複雜的。
具體步驟有四個:
const ajaxFunc = ()=>{
// 以 XMLHttpRequest 物件的方法抓取資料
xhr = new XMLHttpRequest()
// 開啟一個請求,這裡使用 GET,true 為非同步的意思
xhr.open('GET',apiUrl, true)
// 送出請求
xhr.send()
xhr.onload = function () {
if(xhr.status === 200){
let data = JSON.parse(this.responseText)
console.log(data)
let user = data.results[0]
name = `${user.name.first} ${user.name.last}`
img = user.picture.large
email = user.email
show.innerHTML = `<h3>${name}</h3> <img src=${img}> <p>${email}</p>`
}else{
console.error(error)
}
}
}
find.addEventListener('click',()=>{
ajaxFunc()
})
在onload
的部分,我有用console.log(data)
來檢視瀏覽器所取得的資料,會長像下圖那樣,其實就是 RANDOM USER GENERATOR 裡面說的會拿到的資料啦。
備註一下,接下來我所有的 API 串接方法都會包在一個函式裡面 (像是 ajaxFunc
),然後再把它綁到事件監聽器去。
這個是使用 jQuery 函式庫提供的 Ajax 方法,它簡化了非同步請求的程式碼。但因為它必須使用到 jQuery,所以必須先把它載入到專案中。
// 在 HTML 的 head 中加入這段
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
然後接下來我們可以看看它的寫法:
const jAjaxFunc = ()=>{
$.ajax({
url: apiUrl,
type: 'GET',
dataType: 'json',
success: function (data) {
let user = data.results[0]
name = `${user.name.first} ${user.name.last}`
img = user.picture.large
email = user.email
show.innerHTML =
`<h3>${name}</h3> <img src=${img}> <p>${email}</p>`
},
error: function (error) {
console.error(error)
}
})
}
find.addEventListener('click', ()=>{
jAjaxFunc()
})
也就是它會列出:
嗯,比起 Ajax,語法已經較清晰好理解了,但似乎還是不夠直觀?沒關係,後面還有兩個方法壓軸。
作為相對年輕的 API 串接方法,它是基於 Promise 語法的 API 串接方式,變得更簡潔、更好讀了。
用 Fetch API,上面的 code 會變這樣:
const fetchFunc = ()=>{
fetch(apiUrl)
.then(response => response.json())
.then(data =>{
console.log(data)
let user = data.results[0]
name = `${user.name.first} ${user.name.last}`
img = user.picture.large
email = user.email
show.innerHTML = ` <h3>${name}</h3> <img src=${img}> <p>${email}</p>`
})
.catch(error => console.log(error))
}
find.addEventListener('click', ()=>{
fetchFunc()
})
看,感覺又直觀清楚了許多,最後來看看 Axios。
Axios 跟 Fetch API 一樣都是比較新的 API 串接方法,並且同樣也是基於 Promise,在提供非同步處理時也讓整個程式碼更簡潔易讀。
不過因為 Axios 是屬於第三方函式庫,所以使用前必須先引入:
// 在 HTML 的 head 中加入這段
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
或是可以直接透過npm install axios
把整個 Axios 函式庫裝入本地專案中,那這樣我們必須在 JavaScript 檔案中把 Axios 給引入:
import axios from 'axios'
接下來直接來看用 Axios 做串接,上面的程式碼會變怎樣。
const axiosFunc = ()=>{
axios
.get(apiUrl)
.then((response) => {
console.log(response.data)
let user = response.data.results[0];
name = `${user.name.first} ${user.name.last}`;
img = user.picture.large;
email = user.email;
show.innerHTML =
`<h3>${name}</h3> <img src=${img}> <p>${email}</p>`;
})
.catch((error) => console.log(error));
}
find.addEventListener('click', ()=>{
axiosFunc()
})
看起來是不是長得跟 Fetch API 很類似,但他們還是有些差異的,比如 Fetch API 會需要我們手動進行 JSON 解析,所以需要response.json()
,而 Axios 會直接幫我們解析 JSON。同時 Axios 預設也會自動處理所有的 HTTP 狀態,包括錯誤的狀態,所以平心而論,Axios 還是提供了比較多的便利功能。
我不知道大家有沒有這個疑惑:為什麼我不把show.innerHTML
寫在事件監聽器裡,而是寫在 API 的串接函式中。
// 原本的寫法
find.addEventListener('click', ()=>{
axiosFunc()
})
// 更改後的寫法
find.addEventListener('click', ()=>{
axiosFunc()
show.innerHTML =
`<h3>${name}</h3> <img src=${img}> <p>${email}</p>`
})
使用下面更改後的寫法,會發現我在第一次點擊按鈕時並沒有畫面跑出來,但第二次之後的點擊就有了,為什麼?
其實這裡跟非同步機制有關,下面更改後的寫法當我們點擊按鈕時的確會先觸發 axiosFunc
,但是要注意,axiosFuc
帶著的實際上是一個非同步請求,所以他不會去阻塞後續程式碼的執行,所以當show.innerHTML
執行時,name、img、email 實際上是還沒被賦值的。大家可以參考一下JS 筆記 | Event Loop,會清楚很多。