Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JS 口袋书】第 10 章:使用异步 JavaScript #135

Open
husky-dot opened this issue Oct 30, 2019 · 0 comments
Open

【JS 口袋书】第 10 章:使用异步 JavaScript #135

husky-dot opened this issue Oct 30, 2019 · 0 comments

Comments

@husky-dot
Copy link
Owner

husky-dot commented Oct 30, 2019

作者:valentinogagliardi
译者:前端小智
来源:github


阿里云最近在做活动,低至2折,真心觉得很划算了,可以点击本条内容或者链接进行参与
https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r


REST API 和 XMLHttpRequest

如果你问我,我会说 JS 挺强大的。作为一种在浏览器中运行的脚本语言,它可以做所有类似的事情:

  • 动态创建元素
  • 添加互动性

等等。在第 8 章中,咱们从数组开始构建了一个 HTML 表格。 硬编码数组是一个同步数据源,也就是说,可以直接在咱们的代码中使用它,无需等待。 但是大多数时候,数据都是从后台请求过来的。网络请求始终是异步操作,而不是同步数据源:请求数据,服务器会有一定的延迟后才响应。

JS 本身没有内置的异步性:它是“宿主”环境(浏览器或 Node.j),为处理耗时的操作提供了外部帮助。在第3章中,咱们看到了setTimeoutsetInterval,这两个属于 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事件的,咱们可以使用 addEventListeneronload 来监听“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不支持该字段)。在编写任何代码之前,都要思考一下,别人会“如何使用我的类”? 例如,另一个开发人员可以使用咱们的代码并通过传入来调用该类:

有了这些要求,咱们就可以开始编写类代码了。目前,它应该接受构造函数中的两个参数,并拥有一个获取数据方法

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 正确,则打印请求到数据:

上述实现方式还不够完善。首先,咱们需要实现一个返回 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

交流

阿(a)里(li)云(yun)最近在做活动,低至2折,有兴趣可以看看:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq449245884/xiaozhi

因为篇幅的限制,今天的分享只到这里。如果大家想了解更多的内容的话,可以去扫一扫每篇文章最下面的二维码,然后关注咱们的微信公众号,了解更多的资讯和有价值的内容。

clipboard.png

每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant