【JS 口袋書】第 10 章:使用異步 JavaScript

做者:valentinogagliardi
譯者:前端小智
來源:github

阿里雲服務器很便宜火爆,今年比去年便宜,10.24~11.11購買是1年86元,3年229元,能夠點擊 下面連接進行參與:
https://www.aliyun.com/1111/2...javascript


REST API 和 XMLHttpRequest

若是你問我,我會說 JS 挺強大的。做爲一種在瀏覽器中運行的腳本語言,它能夠作全部相似的事情:html

  • 動態建立元素
  • 添加互動性

等等。在第 8 章中,我們從數組開始構建了一個 HTML 表格。 硬編碼數組是一個同步數據源,也就是說,能夠直接在我們的代碼中使用它,無需等待。 可是大多數時候,數據都是從後臺請求過來的。網絡請求始終是異步操做,而不是同步數據源:請求數據,服務器會有必定的延遲後才響應。前端

JS 自己沒有內置的異步性:它是「宿主」環境(瀏覽器或 Node.j),爲處理耗時的操做提供了外部幫助。在第3章中,我們看到了setTimeoutsetInterval,這兩個屬於 Web API 的。瀏覽器提供了不少 API,其中還有一個叫XMLHttpRequest,專門用於網絡請求。java

事實上,它來自於以 XML 數據格式的時代。如今 JSON 是最流行的用於在 Web 服務之間移動數據的通訊「協議」,但 XMLHttpRequest 這個名稱最終被保留了下來。ios

XMLHttpRequest 也是 AJAX 技術的一部分,它是 「異步JavaScript和XML」 的縮寫。AJAX 就是爲了在瀏覽器中儘量靈活地處理網絡請求而誕生的。它的做用是可以從遠程數據源獲取數據,而不會致使頁面刷新。當時這個想法幾乎是革命性的。隨着 XMLHttpRequest (大約13年前)的引入,我們可使用它來進行異步請求。git

var request = new XMLHttpRequest();

request.open('GET', "https://academy.valentinog.com/api/link/");

request.addEventListener('load', function() {
  console.log(this.response);
})

request.send();

在上述的示例中:github

  • 建立一個新的 XMLHttpRequest 對象
  • 經過提供方法和網址來打開請求
  • 註冊事件監聽器
  • 發送請求

XMLHttpRequest 是基於DOM事件的,我們可使用 addEventListeneronload 來監聽「load」事件,該事件在請求成功時觸發。對於失敗的請求(網絡錯誤),我們能夠在「error」事件上註冊一個偵聽器:web

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 的文件:json

<!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 = "https://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";
  }
}

你可能不喜歡語法,可是私有類字段能夠完成其工做。 這種方式,咱們就不能從外部訪問 urltarget

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並在瀏覽器控制檯中再次查看 Scopesresponseundefined ,由於咱們要訪問的 thisList。這與箭頭函數和類的行爲一致(類默認爲嚴格模式)。那麼如今有什麼解決辦法嗎?

第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);
  });

FetchXMLHttpRequest 更方便、更乾淨,但它有不少特性。例如,必須特別注意檢查響應中的錯誤。在下一節中,我們將瞭解關於它的更多信息,同時從頭從新構建 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();
  });
}

被拒絕的 Promisecatch 處理:

fetch("https://acdemy.valentinog.com/api/link/")
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

如今,若是 url 是錯誤的,會打印具體的錯誤信息到控制檯。若是 url 正確,則打印請求到數據:

clipboard.png

上述實現方式還不夠完善。首先,我們須要實現一個返回 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.oktrue

  • 狀態碼等於或小於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 中的 bodymethodheaders

首先,建立一個帶有一些名爲 bodymethodheaders 的屬性的新 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 的邏輯能夠獨立存在於方法上。

此外,還有很大的空間能夠添加新特性:支持 PUTDELETE 以及更多以不一樣格式返回響應的函數。若是你想看到更復雜的獲取 API polyfill,請查看來自 Github的 工程師的 whatwg-fetch。你會發現與我們的 polyfill 有不少類似之處。

總結

AJAX 讓咱們有機會構建流暢的、用戶友好的界面,從而改變了咱們構建 web 的方式。經典頁面刷新的日子已經一去不復返了。

如今,我們能夠構建優雅的 JS 應用程序並在後臺獲取所需的數據。XMLHttpRequest 是用於發出HTTP 請求的優秀的舊遺留的 API,今天仍在使用,但其形式有所不一樣: Fetch API

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具Fundebug

原文:https://github.com/valentinogagliardi/Little-JavaScript-Book/blob/v1.0.0/manuscript/chapter9.md

交流

阿里雲最近在作活動,低至2折,有興趣能夠看看:https://promotion.aliyun.com/...

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

https://github.com/qq449245884/xiaozhi

由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。

clipboard.png

每次整理文章,通常都到2點才睡覺,一週4次左右,挺苦的,還望支持,給點鼓勵

相關文章
相關標籤/搜索