作者:valentinogagliardi
譯者:前端小智
來源:github
REST API 和 XMLHttpRequest
如果你問我,我會說 JS 挺強大的。作為一種在瀏覽器中執行的指令碼語言,它可以做所有類似的事情:
- 動態建立元素
- 新增互動性
等等。在第 8
章中,我們們從陣列開始構建了一個 HTML 表格。 硬編碼陣列是一個同步資料來源,也就是說,可以直接在我們們的程式碼中使用它,無需等待。 但是大多數時候,資料都是從後臺請求過來的。網路請求始終是非同步操作,而不是同步資料來源:請求資料,伺服器會有一定的延遲後才響應。
JS 本身沒有內建的非同步性:它是“宿主”環境(瀏覽器或 Node.j),為處理耗時的操作提供了外部幫助。在第3章中,我們們看到了setTimeout
和 setInterval
,這兩個屬於 Web API
的。瀏覽器提供了很多 API,其中還有一個叫XMLHttpRequest
,專門用於網路請求。
事實上,它來自於以 XML 資料格式的時代。現在 JSON
是最流行的用於在 Web 服務之間移動資料的通訊“協議”,但 XMLHttpRequest
這個名稱最終被保留了下來。
XMLHttpRequest
也是 AJAX
技術的一部分,它是 “非同步JavaScript和XML” 的縮寫。AJAX 就是為了在瀏覽器中儘可能靈活地處理網路請求而誕生的。它的作用是能夠從遠端資料來源獲取資料,而不會導致頁面重新整理。當時這個想法幾乎是革命性的。隨著 XMLHttpRequest (大約13年前)的引入,我們們可以使用它來進行非同步請求。
var request = new XMLHttpRequest();
request.open('GET', "https://academy.valentinog.com/api/link/");
request.addEventListener('load', function() {
console.log(this.response);
})
request.send();
複製程式碼
在上述的示例中:
-
建立一個新的
XMLHttpRequest
物件 -
通過提供方法和網址來開啟請求
-
註冊事件監聽器
-
傳送請求
XMLHttpRequest 是基於DOM事件的,我們們可以使用 addEventListener
或 onload
來監聽“load
”事件,該事件在請求成功時觸發。對於失敗的請求(網路錯誤),我們們可以在“error
”事件上註冊一個偵聽器:
var request = new XMLHttpRequest();
request.open("GET", "https://academy.valentinog.com/api/link/")
request.onload = function() {
console.log(this.response)
}
request.onerror = function() {
// 處理錯誤
}
request.send();
複製程式碼
有了這些知識,我們們就更好地使用 XMLHttpRequest
。
通過 XMLHttpRequest 請求資料,構建 HTML 列表
從 REST API 提取資料後,我們們將構建一個簡單的 HTML 列表。 新建一個名為 build-list.html 的檔案:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>XMLHttpRequest</title>
</head>
<body>
</body>
<script src="xhr.js"></script>
</html>
複製程式碼
接下來,在同一個資料夾中建立一個名為 xhr.js 的檔案。在這個檔案中,建立一個新的 XHR 請求:
"use strict";
const request = new XMLHttpRequest();
複製程式碼
上面的呼叫(建構函式方式)建立了一個 XMLHttpRequest
型別的新物件。與 setTimeout
等非同步函式相反,我們把回撥作為引數:
setTimeout(callback, 10000);
function callback() {
console.log("hello timer!");
}
複製程式碼
XMLHttpRequest
基於 DOM 事件,處理程式回撥註冊在 onload
物件上。當請求成功時,load
事件觸發。
"use strict";
const request = new XMLHttpRequest();
request.onload = callback;
function callback() {
console.log("Got the response!");
}
複製程式碼
註冊回撥之後,我們可以使用 open()
開啟請求。它接受一個 HTTP
方法
"use strict";
const request = new XMLHttpRequest();
request.onload = callback;
function callback() {
console.log("Got the response!");
}
request.open("GET", "https://academy.valentinog.com/api/link/");
複製程式碼
最後,我們可以使用 send()
傳送實際的請求
"use strict";
const request = new XMLHttpRequest();
request.onload = callback;
function callback() {
console.log("Got the response!");
}
request.open("GET", "https://academy.valentinog.com/api/link/");
request.send();
複製程式碼
在瀏覽器中開啟 build-list.html,在控制檯中會看到“Got the response!”
,說明請求成功。如果你還記得第6章,每個常規 JS 函式都有一個對其宿主物件的引用。因為回撥在 XMLHttpRequest
物件中執行,所以可以通過 this.response
獲取伺服器返回的資料。
"use strict";
const request = new XMLHttpRequest();
request.onload = callback;
function callback() {
// this refers to the new XMLHttpRequest
// response is the server's response
console.log(this.response);
}
request.open("GET", "https://academy.valentinog.com/api/link/");
request.send();
複製程式碼
儲存檔案並重新整理 build-list.html。在控制檯可以看到返回的資料,資料格式是字串,有兩種方法可以把它變成 JSON 格式:
-
方法一:在
XMLHttpRequest
物件上配置響應型別 -
方法二:使用
JSON.parse()
方法一:
"use strict";
const request = new XMLHttpRequest();
request.onload = callback;
function callback() {
// this refers to the new XMLHttpRequest
// response is the server's response
console.log(this.response);
}
// configure the response type
request.responseType = "json";
//
request.open("GET", "https://academy.valentinog.com/api/link/");
request.send();
複製程式碼
方法二 比較推薦,也符合我們們現在的程式設計習慣:
"use strict";
const request = new XMLHttpRequest();
request.onload = callback;
function callback() {
const response = JSON.parse(this.response);
console.log(response);
}
request.open("GET", "https://academy.valentinog.com/api/link/");
request.send();
複製程式碼
再次重新整理build-list.html,會看到一個 JS 物件陣列,每個物件都具有相同的結構:
[
//
{
title:
"JavaScript Engines: From Call Stack to Promise, (almost) Everything You Need to Know",
url: "https://www.valentinog.com/blog/engines/",
tags: ["javascript", "v8"],
id: 3
}
//
]
複製程式碼
這次,我們們沒有像第8章那樣手工建立陣列,而是通過 REST API 介面請求資料。
使用 JS 構建 HTML 列表(和除錯類)
這裡我們們使用 ES6 類的方法來構建,還會使用私有類欄位(在撰寫本文時,Firefox不支援該欄位)。在編寫任何程式碼之前,都要思考一下,別人會“如何使用我的類”? 例如,另一個開發人員可以使用我們們的程式碼並通過傳入來呼叫該類:
-
用於獲取資料的 URL
-
要將列表附加到的 HTML 元素
const url = "academy.valentinog.com/api/link/"; const target = document.body; const list = new List(url, target);
有了這些要求,我們們就可以開始編寫類程式碼了。目前,它應該接受建構函式中的兩個引數,並擁有一個獲取資料方法
class List {
constructor(url, target) {
this.url = url;
this.target = target;
}
getData() {
return "stuff";
}
}
複製程式碼
軟體開發中的普遍觀點是,除非有充分的理由要做相反的事情,否則不能從外部訪問類成員和方法。 在 JS 中,除非使用模組,否則沒有隱藏方法和變數的原生方法(第2章)。 即使是 class
也不能倖免於資訊洩漏,但是有了私有欄位,就能大概率避免這類問題。 JS 私有類欄位的目前還沒有成標準,但大部分瀏覽器已經支援了,它用 #
來表示,重寫上面的類:
class List {
#url;
#target;
constructor(url, target) {
this.#url = url;
this.#target = target;
}
getData() {
return "stuff";
}
}
複製程式碼
你可能不喜歡語法,但是私有類欄位可以完成其工作。 這種方式,我們就不能從外部訪問 url
和 target
:
class List {
#url;
#target;
constructor(url, target) {
this.#url = url;
this.#target = target;
}
getData() {
return "stuff";
}
}
const url = "https://academy.valentinog.com/api/link/";
const target = document.body;
const list = new List(url, target);
console.log(list.url); // undefined
console.log(list.target); // undefined
複製程式碼
有了這個結構,我們們就可以將資料獲取邏輯移到 getData
中。
"use strict";
class List {
#url;
#target;
constructor(url, target) {
this.#url = url;
this.#target = target;
}
getData() {
const request = new XMLHttpRequest();
request.onload = function() {
const response = JSON.parse(this.response);
console.log(response);
};
request.open("GET", this.#url);
request.send();
}
}
const url = "https://academy.valentinog.com/api/link/";
const target = document.body;
const list = new List(url, target);
複製程式碼
現在,為了顯示資料,我們們在 getData
之後新增一個名為 render
的方法。render
將為我們建立一個 HTML 列表,從作為引數傳遞的陣列開始:
"use strict";
class List {
#url;
#target;
constructor(url, target) {
this.#url = url;
this.#target = target;
}
getData() {
const request = new XMLHttpRequest();
request.onload = function() {
const response = JSON.parse(this.response);
console.log(response);
};
request.open("GET", this.#url);
request.send();
}
// The new method
render(data) {
const ul = document.createElement("ul");
for (const element of data) {
const li = document.createElement("li");
const title = document.createTextNode(element.title);
li.appendChild(title);
ul.appendChild(li);
}
this.#target.appendChild(ul);
}
}
複製程式碼
注意 document.createElement()
、document.createTextNode()
和 appendChild()
。我們們在第8章講DOM 操作的時候見過。this.#target
私有欄位將 HTML 列表附加到 DOM。現在,我想:
-
獲取 JSON 響應後呼叫
render
-
當使用者建立一個新的列表“例項”時立即呼叫
getData
為此,我們們在 request.onload
回撥內部呼叫 render
:
getData() {
const request = new XMLHttpRequest();
request.onload = function() {
const response = JSON.parse(this.response);
// Call render after getting the response
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
複製程式碼
另一方面,getData
應該在建構函式中執行:
constructor(url, target) {
this.#url = url;
this.#target = target;
// Call getData as soon as the class is used
this.getData();
}
複製程式碼
完整程式碼:
"use strict";
class List {
#url;
#target;
constructor(url, target) {
this.#url = url;
this.#target = target;
this.getData();
}
getData() {
const request = new XMLHttpRequest();
request.onload = function() {
const response = JSON.parse(this.response);
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
render(data) {
const ul = document.createElement("ul");
for (const element of data) {
const li = document.createElement("li");
const title = document.createTextNode(element.title);
li.appendChild(title);
ul.appendChild(li);
}
this.#target.appendChild(ul);
}
}
const url = "https://academy.valentinog.com/api/link/";
const target = document.body;
const list = new List(url, target);
複製程式碼
嘗試一下:在瀏覽器中重新整理 build-list.html 並檢視控制檯
Uncaught TypeError: this.render is not a function
複製程式碼
this.render
不是函式! 會是什麼呢? 此時,你可能想要達到第6章或更高版本,可以除錯程式碼。 在 getData
中的 this.render(response)
之後,新增 debugger
指令:
getData() {
const request = new XMLHttpRequest();
request.onload = function() {
const response = JSON.parse(this.response);
debugger;
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
複製程式碼
debugger
加了一個所謂的斷點,執行將停止在那裡。現在開啟瀏覽器控制檯並重新整理build-list.html。下面是將在 Chrome 中看到的:
仔細檢視“Scopes”選項卡。getData
中確實有一個 this
,但它指向 XMLHttpRequest
。 換句話說,我們試圖在錯誤的物件上訪問 this.render
。
為什麼 this
不匹配? 這是因為傳遞給 request.onload
的回撥在 XMLHttpRequest 型別的宿主物件中執行,呼叫 const request = request = new XMLHttpRequest()
的結果。解決方法,在前幾章中已經提到過了,可以使用 箭頭函式
。
getData() {
const request = new XMLHttpRequest();
// The arrow function in action
request.onload = () => {
const response = JSON.parse(this.response);
debugger;
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
複製程式碼
重新整理 build-list.html 並檢查它
Uncaught SyntaxError: Unexpected token u in JSON at position 0
複製程式碼
很好,前面的錯誤消失了,但是現在 JSON.parse
出現了一個問題。我們很容易想象它與 this
有關。將debugger
向上移動一行
getData() {
const request = new XMLHttpRequest();
request.onload = () => {
debugger;
const response = JSON.parse(this.response);
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
複製程式碼
重新整理build-list.html並在瀏覽器控制檯中再次檢視 Scopes 。response
是 undefined
,因為我們要訪問的 this
是 List。這與箭頭函式和類的行為一致(類預設為嚴格模式)。那麼現在有什麼解決辦法嗎?
從第8章 DOM 和 events 中瞭解到,作為事件監聽器傳遞的每個回撥都可以訪問 event
物件。在該 event
物件中還有一個名為 target
的屬性,指向觸發事件的物件。吃準可以通過 event.target.response
獲取響應回來的資料。
getData() {
const request = new XMLHttpRequest();
request.onload = event => {
const response = JSON.parse(event.target.response);
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
複製程式碼
完整程式碼:
"use strict";
class List {
#url;
#target;
constructor(url, target) {
this.#url = url;
this.#target = target;
this.getData();
}
getData() {
const request = new XMLHttpRequest();
request.onload = event => {
const response = JSON.parse(event.target.response);
this.render(response);
};
request.open("GET", this.#url);
request.send();
}
render(data) {
const ul = document.createElement("ul");
for (const element of data) {
const li = document.createElement("li");
const title = document.createTextNode(element.title);
li.appendChild(title);
ul.appendChild(li);
}
this.#target.appendChild(ul);
}
}
const url = "https://academy.valentinog.com/api/link/";
const target = document.body;
const list = new List(url, target);
複製程式碼
接著,繼續探索 XMLHttpRequest
的發展:Fetch
。
非同步演變:從 XMLHttpRequest 到 Fetch
Fetch API 是一種用於發出 AJAX
請求的原生瀏覽器方法,它常常被諸如 Axios
之類的庫所忽視。Fetch 與ES6 和新的 Promise
物件一起誕生於 2015 年。
另一方面,AJAX 從 1999 年開始就有了一套在瀏覽器中獲取資料的技術。現在我們認為 AJAX 和 Fetch 是理所當然的,但是很少有人知道 Fetch
只不過是 XMLHttpRequest
的 “美化版
”。Fetch
比典型的 XMLHttpRequest
請求更簡潔,更重要的是基於 Promise
。這裡有一個簡單的事例:
fetch("https://academy.valentinog.com/api/link/").then(function(response) {
console.log(response);
});
複製程式碼
如果在瀏覽器中執行它,控制檯將列印一個響應物件。根據請求的內容型別,需要在返回資料時將其轉換為JSON
fetch("https://academy.valentinog.com/api/link/").then(function(response) {
return response.json();
});
複製程式碼
與你可能認為的相反,僅僅呼叫並沒有返回實際的資料。由於response.json()
也返回一個 Promise
,因此需要進一步才能獲得 JSON 有效負載:
fetch("https://academy.valentinog.com/api/link/")
.then(function(response) {
return response.json();
})
.then(function(json) {
console.log(json);
});
複製程式碼
Fetch
比 XMLHttpRequest
更方便、更乾淨,但它有很多特性。例如,必須特別注意檢查響應中的錯誤。在下一節中,我們們將瞭解關於它的更多資訊,同時從頭重新構建 Fetch
。
從頭開始重新構建 Fetch API
為了更好的理解 Fetch 原理,我們們重寫 fetch
方法。首先,建立一個名為fetch.html的新檔案,內容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Building Fetch from scratch</title>
</head>
<body>
</body>
<script src="fetch.js"></script>
</html>
複製程式碼
然後在相同的資料夾中建立另一個名為 fetch.js 的檔案,內容如下:
"use strict";
window.fetch = null;
複製程式碼
在第一行中,我們們確保處於嚴格模式,在第二行中,“取消”原始的Fetch API。現在我們們可以開始構建自己的 Fetch API 了。fetch
的工作方式非常簡單。它接受一個 url
並針對它發出一個 GET
請求:
fetch("https://academy.valentinog.com/api/link/").then(function(response) {
console.log(response);
});
複製程式碼
當帶有 then
的函式說明該函式是“可鏈”的,這意味著它返回一個 Promise
。因此,在 fetch.js 中,我們們建立一個名為 fetch
的函式,它接受一個 url
並返回一個新的 Promise
。建立 Promise,可以呼叫Promise
建構函式,並傳入一個回撥函式來解析和拒絕:
function fetch(url) {
return new Promise(function(resolve, reject) {
// do stuff
});
}
複製程式碼
完善程式碼:
"use strict";
window.fetch = fetch;
function fetch(url) {
return new Promise(function(resolve, reject) {
resolve("Fake response!");
});
}
fetch("https://academy.valentinog.com/api/link/").then(function(response) {
console.log(response);
});
複製程式碼
在控制檯中得到“Fake response!” 。當然,這仍然是一個無用的 fetch
,因為沒有從 API 返回任何東西。讓我們們在 XMLHttpRequest 的幫助下實現真正的行為。我們們已經知道了 XMLHttpRequest 建立請求方式。接著,將XMLHttpRequest
封裝到我們們的 Promise 中
function fetch(url) {
return new Promise(function(resolve, reject) {
const request = new XMLHttpRequest();
request.open("GET", url);
request.onload = function() {
resolve(this.response);
};
request.onerror = function() {
reject("Network error!");
};
request.send();
});
}
複製程式碼
被拒絕的 Promise 由 catch
處理:
fetch("https://acdemy.valentinog.com/api/link/")
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
複製程式碼
現在,如果 url
是錯誤的,會列印具體的錯誤資訊到控制檯。如果 url
正確,則列印請求到資料:
上述實現方式還不夠完善。首先,我們們需要實現一個返回 JSON
的函式。實際的 Fetch API 生成一個響應,可以稍後將其轉換為 JSON、blob 或 文字,如下所示(對於本練習的範圍,我們只實現 JSON 函式)
fetch("https://academy.valentinog.com/api/link/")
.then(function(response) {
return response.json();
})
.then(function(json) {
console.log(json);
})
複製程式碼
實現該功能應該很容易。 似乎 “response
” 可能是一個單獨帶有 json()
函式的實體。 JS 原型系統非常適合構建程式碼(請參閱第5章)。 我們們建立一個名為 Response 的建構函式和一個繫結到其原型的方法(在fetch.js中):
function Response(response) {
this.response = response;
}
Response.prototype.json = function() {
return JSON.parse(this.response);
};
複製程式碼
就這樣,我們們我們可以在 Fetch 中使用 Response:
window.fetch = fetch;
function Response(response) {
this.response = response;
}
Response.prototype.json = function() {
return JSON.parse(this.response);
};
function fetch(url) {
return new Promise(function(resolve, reject) {
const request = new XMLHttpRequest();
request.open("GET", url);
request.onload = function() {
// 前面:
// resolve(this.response);
// 現在:
const response = new Response(this.response);
resolve(response);
};
request.onerror = function() {
reject("Network error!");
};
request.send();
});
}
fetch("https://academy.valentinog.com/api/link/")
.then(function(response) {
return response.json();
})
.then(function(json) {
console.log(json);
})
.catch(function(error) {
console.log(error);
});
複製程式碼
上面的程式碼在瀏覽器的控制檯中列印一個物件陣列。現在我們們來處理誤差。Fetch 的真實版本比我們的 polyfill
複雜得多,但是實現相同的行為並不困難。Fetch 中的響應物件有一個屬性,一個名為**“ok”**的布林值。該布林值在請求成功時設定為 true
,在請求失敗時設定為 false
。開發人員可以通過引發錯誤來檢查布林值並更改 Promise
處理程式。 這是使用實際 Fetch
檢查狀態的方法:
fetch("https://academy.valentinog.com/api/link/")
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(json) {
console.log(json);
})
.catch(function(error) {
console.log(error);
});
複製程式碼
如你所見,還有一個 "statusText"
。 在 Response 物件中似乎容易實現 "ok"
和 "statusText"
。 當伺服器響應成功,response.ok
為 true
:
- 狀態碼等於或小於200
- 狀態碼小於 300
重構 Response
方法,如下所示:
function Response(response) {
this.response = response.response;
this.ok = response.status >= 200 && response.status < 300;
this.statusText = response.statusText;
}
複製程式碼
這裡不需要建立 "statusText
",因為它已經從原始 XMLHttpRequest 響應物件返回了。這意味著在構造自定義響應時只需要傳遞整個響應
function fetch(url) {
return new Promise(function(resolve, reject) {
const request = new XMLHttpRequest();
request.open("GET", url);
request.onload = function() {
// 前面:
// var response = new Response(this.response);
// 現在: pass the entire response
const response = new Response(this);
resolve(response);
};
request.onerror = function() {
reject("Network error!");
};
request.send();
});
}
複製程式碼
但是現在我們們的 polyfill 有問題。 它接受單個引數 "url
",並且僅對其發出 GET 請求。修復這個問題應該很容易。首先,我們可以接受第二個名為requestInit
的引數。然後根據該引數,我們可以構造一個新的請求物件:
- 預設情況下,發出 GET 請求
- 如果提供,則使用 requestInit 中的
body
、method
和headers
首先,建立一個帶有一些名為 body
,method
和 headers
的屬性的新 Request
函式,如下所示:
function Request(requestInit) {
this.method = requestInit.method || "GET";
this.body = requestInit.body;
this.headers = requestInit.headers;
}
複製程式碼
但在此之上,我們可以為設定請求頭新增一個最小的邏輯
function fetch(url, requestInit) {
return new Promise(function(resolve, reject) {
const request = new XMLHttpRequest();
const requestConfiguration = new Request(requestInit || {});
request.open(requestConfiguration.method, url);
request.onload = function() {
const response = new Response(this);
resolve(response);
};
request.onerror = function() {
reject("Network error!");
};
// 設定 headers
for (const header in requestConfiguration.headers) {
request.setRequestHeader(header, requestConfiguration.headers[header]);
}
// more soon
});
}
複製程式碼
setRequestHeader
可以在 XMLHttpRequest 物件上直接使用。 headers
對於配置 AJAX 請求很重要。 大多數時候,你可能想在 headers
中設定 application/json
或身份驗證令牌。
- 如果沒有 body,則為空請求
- 帶有一些有效負載的請求是
body
提供的
function fetch(url, requestInit) {
return new Promise(function(resolve, reject) {
const request = new XMLHttpRequest();
const requestConfiguration = new Request(requestInit || {});
request.open(requestConfiguration.method, url);
request.onload = function() {
const response = new Response(this);
resolve(response);
};
request.onerror = function() {
reject("Network error!");
};
// Set headers on the request
for (const header in requestConfiguration.headers) {
request.setRequestHeader(header, requestConfiguration.headers\[header\]);
}
// If there's a body send it
// If not send an empty GET request
requestConfiguration.body && request.send(requestConfiguration.body);
requestConfiguration.body || request.send();
});
}
複製程式碼
下面是完整的程式碼:
"use strict";
window.fetch = fetch;
function Response(response) {
this.response = response.response;
this.ok = response.status >= 200 && response.status < 300;
this.statusText = response.statusText;
}
Response.prototype.json = function() {
return JSON.parse(this.response);
};
function Request(requestInit) {
this.method = requestInit.method || "GET";
this.body = requestInit.body;
this.headers = requestInit.headers;
}
function fetch(url, requestInit) {
return new Promise(function(resolve, reject) {
const request = new XMLHttpRequest();
const requestConfiguration = new Request(requestInit || {});
request.open(requestConfiguration.method, url);
request.onload = function() {
const response = new Response(this);
resolve(response);
};
request.onerror = function() {
reject("Network error!");
};
for (const header in requestConfiguration.headers) {
request.setRequestHeader(header, requestConfiguration.headers[header]);
}
requestConfiguration.body && request.send(requestConfiguration.body);
requestConfiguration.body || request.send();
});
}
const link = {
title: "Building a Fetch Polyfill From Scratch",
url: "https://www.valentinog.com/fetch-api/"
};
const requestInit = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(link)
};
fetch("https://academy.valentinog.com/api/link/create/", requestInit)
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(json) {
console.log(json);
})
.catch(function(error) {
console.log(error);
});
複製程式碼
真正的 Fetch API 實現要複雜得多,並且支援高階特性。我們只是觸及了表面。可以改進程式碼,例如,新增 headers
的邏輯可以獨立存在於方法上。
此外,還有很大的空間可以新增新特性:支援 PUT 和 DELETE 以及更多以不同格式返回響應的函式。如果你想看到更復雜的獲取 API polyfill,請檢視來自 Github的 工程師的 whatwg-fetch。你會發現與我們們的 polyfill
有很多相似之處。
總結
AJAX 讓我們有機會構建流暢的、使用者友好的介面,從而改變了我們構建 web 的方式。經典頁面重新整理的日子已經一去不復返了。
現在,我們們可以構建優雅的 JS 應用程式並在後臺獲取所需的資料。XMLHttpRequest 是用於發出HTTP 請求的優秀的舊遺留的 API,今天仍在使用,但其形式有所不同: Fetch API。
程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具Fundebug。
交流
乾貨系列文章彙總如下,覺得不錯點個Star,歡迎 加群 互相學習。
因為篇幅的限制,今天的分享只到這裡。如果大家想了解更多的內容的話,可以去掃一掃每篇文章最下面的二維碼,然後關注我們們的微信公眾號,瞭解更多的資訊和有價值的內容。
每次整理文章,一般都到2點才睡覺,一週4次左右,挺苦的,還望支援,給點鼓勵