做者:valentinogagliardijavascript
譯者:前端小智html
來源:github前端
阿(a)裏(li)雲(yun)服務器很便宜火爆,今年比去年便宜,10.24~11.11購買是1年86元,3年229元,能夠點擊我 進行參與java
若是你問我,我會說 JS 挺強大的。做爲一種在瀏覽器中運行的腳本語言,它能夠作全部相似的事情:ios
等等。在第 8
章中,我們從數組開始構建了一個 HTML 表格。 硬編碼數組是一個同步數據源,也就是說,能夠直接在我們的代碼中使用它,無需等待。 可是大多數時候,數據都是從後臺請求過來的。網絡請求始終是異步操做,而不是同步數據源:請求數據,服務器會有必定的延遲後才響應。git
JS 自己沒有內置的異步性:它是「宿主」環境(瀏覽器或 Node.j),爲處理耗時的操做提供了外部幫助。在第3章中,我們看到了setTimeout
和 setInterval
,這兩個屬於 Web API
的。瀏覽器提供了不少 API,其中還有一個叫XMLHttpRequest
,專門用於網絡請求。github
事實上,它來自於以 XML 數據格式的時代。如今 JSON
是最流行的用於在 Web 服務之間移動數據的通訊「協議」,但 XMLHttpRequest
這個名稱最終被保留了下來。web
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();
複製代碼
在上述的示例中:json
建立一個新的 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
。
從 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 接口請求數據。
這裏我們使用 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
。
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 原理,我們重寫 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
:
重構 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
的參數。而後根據該參數,咱們能夠構造一個新的請求對象:
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
提供的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。
阿(a)裏(li)雲(yun)最近在作活動,低至2折,有興趣能夠看看:promotion.aliyun.com/ntms/yunpar…
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。
每次整理文章,通常都到2點才睡覺,一週4次左右,挺苦的,還望支持,給點鼓勵