文章目錄1. 什麼是 AJAX?2. 什麼是 AJAX:實現非同步網頁通訊的技術2.1. XMLHttpRequest:傳統的 AJAX 實作方式2.1.1. jQuery AJAX:簡化原生通訊的熱門函式庫2.2. Promise:處理非同步操作的現代標準2.2.1. Async/Await:讓非同步程式碼更簡潔的語法糖2.2.2. Fetch API:現代瀏覽器內建的新一代請求介面2.2.3. Axios:功能強大且易用的 HTTP Client 函式庫3. AJAX 打 API 避免快取的實用技巧4. 系列文章導覽5. FAQ:AJAX 常見問題5.1. Q1:我該選原生 Fetch 還是 Axios?5.2. Q2:為什麼 Fetch 在 HTTP 404 時不會跳到 .catch?5.3. Q3:如何處理跨網域 (CORS) 的 AJAX 請求?什麼是 AJAX?AJAX (Asynchronous JavaScript and XML) 是一種允許網頁在「不重新整理整個頁面」的情況下,透過 JavaScript 與伺服器進行非同步資料交換的技術。由於 JavaScript 是單執行緒運作,若採用同步請求會導致瀏覽器在等待回應時完全卡死;AJAX 解決了這個痛點,讓網頁能只更新局部內容(如更新購物車、載入評論)。雖然名稱包含 XML,但現代開發已全面轉向更輕量的 JSON 格式。從傳統的 XMLHttpRequest (XHR) 到現代內建的 Fetch API,以及強大的第三方庫 Axios,掌握這些 HTTP Client 實作方式是前端工程師處理資料流、優化使用者體驗的核心基本功。
在前面幾篇文章,小編介紹了 什麼是 RESTful API、API 系統設計方法、Web API 實作解析。接下來,這份 AJAX 完全指南 就來介紹怎麼透過 AJAX 這個技術和後端的 Web API 溝通。
以男女交往來說重要的溝通是:
丟球: 會不會丟球,不會丟球對方就不知道該怎麼和你進一步互動。接球: 對方丟球該怎麼接到,該怎麼看到球飛過來。當後端的 Web API 開好後,前端也要能夠知道該怎麼對後端發出請求,也才能夠做到良好的互動。掌握 XMLHttpRequest 或 Fetch API 便是關鍵。
什麼是 AJAX:實現非同步網頁通訊的技術AJAX(Asynchronous JavaScript And XML),直接用翻譯看就是非同步 JavaScript 與 XML,雖然是寫 XML 但也可以用現今廣泛使用的 JSON 來做資料交換。
因為 JavaScript 單線程一次只能做一件事,在發送請求到伺服器時會需要等待回覆,若這時伺服器一直沒回應,在單線程的情況下其他任務會被卡死,因此也才有了非同步請求。AJAX 可以讓網頁能夠只更新需要的部分,而無須重新載入整個頁面。
XMLHttpRequest:傳統的 AJAX 實作方式W3C 標準的非同步請求是利用 XMLHttpRequest 寫法:
優點: 簡單直觀所有相關操作都從這個物件去取得缺點: 結構會不漂亮,所以後來 jQuery AJAX 以原生的標準為基礎,封裝後讓寫法更好XMLHttpRequest 是一個能夠取得伺服器端的資料的物件,取得資料的方式可以為非同步 (asynchronously) 或同步 (synchronously)。
發出 request,需叫用 HTTP request 類別的 open() 及 send() 兩個方法
send(): 發出 request,若為 POST 可以帶入資料open(): request 相關設定,有三個參數第一個參數為 HTTP request 的方法 (全大寫)GET: 請求資源POST: 新增資源PUT: 取代資源PATCH: 更新資源DELETE: 刪除資源第二個參數為 URL: 預設會擋 CORS第三個參數為是否非同步,預設是非同步發出 request 後,要檢查 request 目前的 readyState。
如果狀態值為 4 代表伺服器已經傳回所有資訊了,readyState 所有可能的值如下:
0: 還沒開始1: 讀取中2: 已讀取3: 資訊交換中4: 完成123456789101112131415161718192021var data = null;var xhr = new XMLHttpRequest();xhr.withCredentials = true;xhr.addEventListener("readystatechange", function () { if (this.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { // 萬事具備 console.log(this.responseText); } }});xhr.open( "GET", "https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json");xhr.setRequestHeader("cache-control", "no-cache");xhr.send(data);jQuery AJAX:簡化原生通訊的熱門函式庫jQuery 的 Ajax 則以原生的標準為基礎,封裝後讓寫法更好,大幅簡化程式且提供多種方法。
$.get(url,data,callback): get 傳送 data 到 url,並透過 callback 取得執行指令與 url 結果$.post(url,data,callback) 同上,但以 post 傳送 data 到 url$.ajax(setting) 完整的 Ajax 控制語法,setting 為多資料之物件結構陣列12345678910111213var settings = { async: true, crossDomain: true, url: "https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json", method: "GET", headers: { "cache-control": "no-cache", },};$.ajax(settings).done(function (response) { console.log(response);});Promise:處理非同步操作的現代標準Promise 是承諾的意思,可以想成不管是否完成都會告知結果。這是在 JavaScript 中處理非同步程式碼的一種新風格樣式。
代表瀏覽器說著:「我承諾我會盡快給予你一個答覆」
Promise 是在 JavaScript 中非同步程式碼的一種新風格樣式,目前已經實作在各大主流瀏覽器中,定義可以看這個網頁。
Promise 建立之後,要不成功要不失敗,一個好例子是 fetch API,它基本上就是新一代的 XMLHttpRequest,另外 Async/Await 是 Promise 下一代的解決方案,把 then 取代成 Async/Await 後,就能按照同步的語法撰寫。
1234567function asyncFunction(value) { return new Promise(function (resolve, reject) { if (value) resolve(value); // 已實現,成功 else reject(reason); // 有錯誤,已拒絕,失敗 });}主要使用 then 及丟進去的 callback 去取值出來,這裡的 callback 就都是非同步執行的喔!!!
123asyncFunction("test").then(function (datums) { console.log(datums);});promise.all,適合用在多支 API 要一起執行,並確保全部完成後才進行其他工作時。
123Promise.all([promise(1), promise(2), promise(3, 5000)]).then((res) => { console.log(res);});promise.race,適合用在站點不穩定,同時發送多支同行為 API 確保可行性使用。
123Promise.race([promise(1), promise(2), promise(3, 5000)]).then((res) => { console.log(res);});promise.allSettled 適合有多個不相互依賴的異步任務才能成功完成 (想知道每個承諾的結果),在所有都已完成或拒絕後完成的 Promise。
123456789const promise1 = Promise.resolve(3);const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, "fail"));const promises = [promise1, promise2];Promise.allSettled(promises).then((results) => results.forEach((result) => console.log(result.status)));Async/Await:讓非同步程式碼更簡潔的語法糖Promise 在設置上可能會有些複雜並難以理解,因此現代瀏覽器實作出 Async 以及 Await。
async 能夠讓函式執行非同步行為await 可以被用在 async 函式內部,讓程式碼繼續執行前去等待一個 Promise 完成這能讓程式碼在一連串的 Promise 的情況時更加簡潔易懂,只要加上 await 就可以直接叫用一個返回 Promise 的函數,程式碼就會直接在那裏等待,直到 Promise 被完成。
123456789101112131415161718async function fetchProducts() { try { const response = await fetch( "https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json" ); if (!response.ok) { throw new Error(`HTTP:${response.status}`); } const json = await response.json(); console.log(json[0].name); } catch (error) { console.error(`${error}`); }}const jsonPromise = fetchProducts();jsonPromise.then((json) => console.log(json[0].name));從 Promise 改成 async/await 優化了什麼
12345678910111213141516function getData() { promiseFn(1) .then((res) => { console.log(res); // 1, 成功 return promiseFn(2); // 鏈接第二次的 Promise 方法 }) .then((res) => { console.log(res); // 2, 成功 });}async function getData() { const data1 = await promiseFn(1); // 因為 await,promise 函式被中止直到回傳 const data2 = await promiseFn(2); console.log(data1, data2); // 1, 成功 2, 成功}Fetch API:現代瀏覽器內建的新一代請求介面在這裡我們看到 fetch() 帶一個 URL 參數並回傳一個 Promise,可以看成是 AJAX 的新版本,詳情可看MDN 的簡介。
看寫法的話就知道是已經基於 promise 來設計的,其中要注意的是預設 fetch 不會收或送 cookie 必須設定 credentials 這個參數才可以。
123456789101112fetch("http://localhost:8080/api/v1/book/1", { method: "get" }) .then(function (response) { //處理 response return response.json(); }) .then(function (json) { let products = json; initialize(products); }) .catch(function (err) { // Error :( });Axios:功能強大且易用的 HTTP Client 函式庫Axios 除了整合上面的功能外,提供了簡化的寫法,是目前前端開發中最受歡迎的 HTTP Client 之一。
123axios.get("http://localhost:8080/api/v1/book/1").then((res) => { console.log(res);});配置基本設定把一些常用的設定或共用一些需要的防呆實作
123456789101112131415161718192021222324252627282930// 基本設定const instance = axios.create({ baseURL: "https://some-domain.com/api/", timeout: 1000, headers: { "X-Custom-Header": "foobar" },});// request interceptor 統一處理邏輯axios.interceptors.request.use( function (config) { // request 送出前 return config; }, function (error) { // request 錯誤 return Promise.reject(error); });// response interceptor 處理回應axios.interceptors.response.use( function (response) { // 可統一針對各種 Status Code 處理 return response; }, function (error) { // 統一錯誤處理 return Promise.reject(error); });Vue.js 的文件也有介紹使用這套函式庫,透過配置將 client 和vue 的 instance 綁在一起,可以直接透過this.$http來叫用。
AJAX 打 API 避免快取的實用技巧將時間或亂數以適當的 ? 或 & 加在 URL 後方就可以做到避免快取且跨瀏覽器相容。
例如:
1234567// 不快取網頁const cachedURL = "http://test.com/index.html";const unCachedURL = "http://test.com/index.html?12345";// 不快取 APIconst cachedAPI = "http://test.com/api/demo?name=test";const unCachedAPI = "http://test.com/api/demo?name=test&12345";系列文章導覽在此系列文章中,我們從基礎的網頁構成出發,逐步深入到後端 API 設計、開發工具、專案架構以及自動化部署。以下是系列文章的導覽:
上一篇:Web API 實作多語言開發實戰下一篇:網頁即時通訊技術全雙工通訊指南或者您可以參考 前後端如何和平相處系列目錄 以獲取完整列表。
FAQ:AJAX 常見問題Q1:我該選原生 Fetch 還是 Axios?A:如果您的專案極小且不希望增加 Bundle Size,Fetch 已經足夠。但對於中大型專案,強烈推薦 Axios。它內建了 JSON 自動轉換、請求超時設定、以及強大的攔截器功能,能大幅減少重複程式碼。
Q2:為什麼 Fetch 在 HTTP 404 時不會跳到 .catch?A:這是 Fetch 的設計特性。它只有在「網路中斷」或「請求被阻擋」時才會拒絕 (Reject)。如果是 HTTP 404 或 500,Fetch 仍視為成功。您必須手動檢查 response.ok 屬性來處理錯誤。
Q3:如何處理跨網域 (CORS) 的 AJAX 請求?A:CORS 主要是伺服器端的設定。伺服器必須在回應標頭中包含 Access-Control-Allow-Origin。若前端需要攜帶 Cookie,請確保後端設定允許並在 AJAX 請求中開啟 withCredentials (XHR) 或 credentials: 'include' (Fetch)。
更多相關文章CSS in JS 應用與優缺點分析2022-09-10想徹底解決 CSS 命名衝突嗎?本篇 CSS in JS 指南深入探討在 React 應用中管理樣式的最佳實踐。我們將解析 styled-components、CSS Modules 與 Facebook 最新 StyleX 的優缺點。前 150 字直接回答 CSS in JS 定義,助您在提升模組化程度的同時做出最佳技術選型。
React 渲染模式 CSR vs. SSR2022-10-02網頁該用 CSR 還是 SSR 渲染?本篇 React 網頁渲染模式指南深入解析兩者差異。我們將探討 SPA 的開發優勢、SSR 對 SEO 的重要性,以及如何透過 Next.js 解決渲染難題。前 150 字直接回答渲染模式定義,助您在提升網頁性能的同時做出正確的架構選型。
JS 開發必備工具與 CI/CD2022-10-09想提升 JavaScript 開發效率嗎?本篇指南深度解析前端開發者不可或缺的工具鏈。我們將探討 Linter 語法檢查、Babel 跨瀏覽器支援、npm 套件管理、Git 版本控制以及 CI/CD 自動化流程。前 150 字直接回答前端工具的核心價值,助您掌握現代網頁開發的工程化思維,打造高品質、易維護的軟體系統。
HTTP Cookies 深度實踐安全2022-09-24想深入了解網頁是如何記住您的嗎?本篇指南深度解析 HTTP Cookies 的原理與實作。我們將探討 Cookie 在狀態管理中的角色,並分享 Express.js 的實戰配置。前 150 字直接回答 Cookie 核心定義,助您透過 HttpOnly 與 Secure 參數有效防範 XSS 攻擊,建構高品質且安全的網頁應用。
前端框架選型三大框架對比2022-10-08想知道如何選擇最適合的前端框架嗎?本篇指南深度對比 React、Vue 與 Angular 的核心特性。我們將從 JavaScript 函式庫基礎、jQuery 的演進到現代元件驅動開發 (CDD) 全面解析。前 150 字直接回答框架定義,助您在專案開發中做出精準的技術決策。
← 上一篇下一篇 →