2024-08-29 JavaScript 系列五:第4課 ── 學會 AJAX 基本原理

課程目標
認識基本的 AJAX 原理

課程內容
這一課來認識大名鼎鼎的 AJAX 觀念

AJAX 全名 Asynchronous JavaScript and XML

簡單來說,就是「非同步從主機取得資料來更新網頁內容」的技術

舊式的網頁,都是瀏覽器向主機發送 HTTP 請求 -> 主機回應一大坨 html 內容 -> 瀏覽器顯示漂亮網頁給用戶看

因為是一次拿到一大坨 html 內容,我們說「網頁上全部內容都是同步取得」

現代的網頁,也是有很多頁面是這樣直接取得,但有更多功能,是依靠非同步取得資料之後來更新的

滑動到網頁下方,動態載入了更多貼文
對內容按讚,按讚成功網頁出現了小變化
聊天室與別人聊天,網頁也是一段一段文字更新
這些都是使用 AJAX 技術的例子

也就是先載入基本網頁內容,再接著根據需求,於不同時間點發送 HTTP 請求取得部份內容,所以叫做非同步

實務上,我們會說「這邊要發一個 AJAX 跟主機要資料」

讓我們拿一個「模擬線上購物網站 API」來當作例子

https://fakestoreapi.com/

發一個 AJAX 取得 ID 為 1 的用戶資料

1
2
3
fetch('https://fakestoreapi.com/users/1')
.then(res=>res.json())
.then(json=>console.log(json))

請在 jsfiddle 試試,看看結果

會看到一個包含信箱、ID、姓名、電話等等欄位的用戶個資,以物件的形式呈現

這邊使用了內建的 fetch 函式,參數放入要呼叫的 API 網址

接著使用 .then() 函式,由於是直接寫在後面,這相當於把 fetch() 回傳的東西,直接當成物件再接著呼叫 .then() 函式,然後再把結果當成物件再呼叫 .then() 一次

也就是跟這段一模一樣

1
2
3
4
5
6
7
var result1 = fetch('https://fakestoreapi.com/users/1');
var result2 = result1.then(res=>res.json());
var result3 = result2.then(json=>console.log(json));

alert(result1)
alert(result2)
alert(result3)

請在 jsfiddle 試試,會發現 console 顯示的個資一樣,這邊用三個 alert 觀察過程中的東西

會發現顯示三次 [object Promise],這個 Promise 是一個進階觀念,這邊不細談,簡單講就是處理非同步請求的一種資料格式

.then() 參數傳進一個箭頭函式,這是省略大括號 {} 的箭頭函式寫法,其實就只是會自動回傳結果的函式寫法而已

但參數放了個函式,看起來有點怪,為何要這樣寫?

記得我們之前寫過的動態綁定 onclick 事件嗎?

1
<button id="my-btn">Click me</button>
1
2
3
4
5
6
7
8
// 第一種寫法
function myFunction()
{
alert('你點擊了按鈕!');
}

var btn = document.getElementById('my-btn');
btn.onclick = myFunction;

網頁元素的事件處理,也是一種「非同步」程式設計

也就是我不確定「點擊」事件何時會發生,但我先「綁定」好事件發生時要做的任務,綁完就讓網頁正常呈現就好

上面的程式碼,可以改寫成這樣

// 第二種寫法

1
2
3
4
var btn = document.getElementById('my-btn');
btn.onclick = () => {
alert('你點擊了按鈕!');
}

如果使用 jQuery,那還可以這樣改寫

// 第三種寫法

1
2
3
$('#my-btn').click(() => {
alert('你點擊了按鈕!');
})

第一種寫法,看起來像是:我先定義好函式,接著把函式名稱當作變數,綁定到 onclick 屬性

第二種寫法,看起來像是:onclick 這邊現場寫一個箭頭函式,把要執行的任務,當場交待清楚

第三種寫法,看起來像是:jQuery 提供的 .click() 函式,會負責把事件綁好,參數傳任務進去就對了

以上三種寫法,效果是完全一模一樣的!

所以你早就接觸過「非同步」程式設計了

也就是「有些任務現在還不會立刻執行,但我先把要執行的任務交待清楚,時間點到的時候,就執行」

以 UI 動作來說,時間點就是 onclick 之時、onchange 之時

以 AJAX 動作來說,時間點就是 拿到主機回應 之時

像這種不是馬上執行的動作,在 JavaScript 領域,我們習慣用「寫一段函式定義當作參數傳進去」來表達!

回頭看一下我們的範例

1
2
3
fetch('https://fakestoreapi.com/users/1')
.then(res=>res.json())
.then(json=>console.log(json))

因為 fetch 第一個回傳的結果,代表的是一個 HTTP 回應物件,這個回應物件的 HTTP body 是實際的 JSON 內容,可以用 .json() 函式取得內容

所以第二個 .then() 的參數,才是我們真正想做的事情

看不懂沒關係,我們多看幾個例子吧

取得全部用戶個資的 AJAX。觀察 console 結果,會看到一個陣列,內含大量個資物件

1
2
3
fetch('https://fakestoreapi.com/users')
.then(res=>res.json())
.then(json=>console.log(json))

取得五筆用戶個資,也是拿到陣列

1
2
3
fetch('https://fakestoreapi.com/users?limit=5')
.then(res=>res.json())
.then(json=>console.log(json))

以上內容,全部通通看不懂沒關係,畢竟,需要多了解一些 HTTP 協定與術語,比較好理解

你就先照做就好:要發 AJAX,就用 fetch() 函式,接著第一個 then() 要執行 .json() 函式,然後第二個函式才是你真正要執行的任務!

課後作業
請使用 https://jsfiddle.net/

請使用「模擬線上購物網站 API」 https://fakestoreapi.com/

假設正在開發一個讀取全部商品資料的頁面

用以下 html 為基礎

1
2
3
4
5
<button>Load Products</button>

<hr>

<ul></ul>

點擊按鈕,發送 AJAX 到 https://fakestoreapi.com/products 請求全部商品資料

拿到資料之後,將每筆資料用以下格式呈現,塞進 <ul> 元素裡面

1
2
3
4
<li>
<span>xxx</span>
<button>Details</button>
</li>

xxx 是商品名稱。點擊 Details 按鈕,連續跳出三個 alert,分別顯示 id category description

請注意,在 for 迴圈裡面綁定 onclick 事件的時候,for 迴圈的參數請加上 const

舉例來說,請這樣寫

1
for (const product of json) {

請「不要」這樣寫

1
for (product of json) {

否則,在迴圈裡面的 onclick 事件,執行起來會有 bug

原因跟上一課提到的 Hoisting 現象有關

我認為這是 JavaScript 的設計失敗,所以詳細原因我不想說明

這是屬於上個世代 JS 工程師的痛苦回憶,這一代的 JS 工程師不需要經歷

現在就用 ES6 語法,宣告變數一律記得加上 const 或 let 就對了

做出以上功能,你就完成這次的課程目標了!

原文取自: https://codelove.tw/@howtomakeaturn/post/VaG5lx by 站長阿川 ·