Skip to main content

AJAX 与 Fetch 简介

· 14 min read
IceyBlackTea

The Fetch API provides an interface for fetching resources (including across the network).

It will seem familiar to anyone who has used XMLHttpRequest,

but the new API provides a more powerful and flexible feature set.

主体内容 2021-03-06 / 2021-03-07
代码修改 2021-03-11

Form 表单提交

前面提过了前后端分离开发,那么前后端交互自然成了开发过程一个重要的部分。

最基础的当然是使用 HTML 自带的功能,通过浏览器控制发送。

比如通过一个 Form 表单提交信息。

下面的 JSX 示例,点击后你填写的信息会提交到 /html/form.html,同时页面也会跳转。

<form action="/html/form.html">
<span>我们组成了一个表单!</span>
<br />
<br />
<span>写点什么吧!</span>
<input type="text" />
<br />
<br />
<input type="submit" value="点我提交!" />
</form>

Form 的表单提交是浏览器自身提供的功能,整个过程不需要别的代码控制,浏览器可以自动完成。

这种方式的缺点也是显而易见的:表单提交的行为会影响整个页面!

如果想要局部刷新页面,我们就需要用到 JavaScript 了。


AJAX 与 XHR

AJAX, which initially stood for Asynchronous JavaScript And XML, is a programming practice of building complex, dynamic webpages using a technology known as XMLHttpRequest.

简单来说,AJAX 是 JavaScript 的一部分,通过 XMLHttpRequest 的 API 来异步(或同步)更新 HTML 页面中的部分 DOM。

示例

例如下面的 JSX 示例,点击后通过 GET 获取 json 数据,更新指定的 div 的内容。

const xhr = new XMLHttpRequest();

const url = '/json/ajax.json'

xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("myDiv").innerHTML =
xhr.responseText;
}
};

xhr.open('GET', url, true);

xhr.send();

AJAX 一般的过程如下:

  • 创建 XHR 对象
  • 发送 XHR 请求
  • 接受 XHR 响应

创建对象

一般情况,调用构造函数即可。

const xhr = new XMLHttpRequest();
兼容性

在旧版本的 IE 浏览器中,你可能需要以 ActiveXObject("Microsoft.XMLHTTP") 代替 XHR

发送请求

与发送有关的方法常用的如下:

方法说明
open(method, url, async)初始化一个请求。
  • method: HTTP 请求方法,如:'GET' 'POST'
  • url: 请求资源的路径
  • async: true(异步) 或 false(同步)
setRequestHeader(header, value)设置HTTP请求头部。
  • header: 属性名称
  • value: 属性值
send(body)发送HTTP请求。
  • body: 发送的数据,可选
  • value: 属性值
abort()终止请求。

使用 AJAX 发送 GET POST 请求的示例如下:

const xhr = new XMLHttpRequest();

xhr.open('GET', url, true);

xhr.send();

接受响应

与响应有关的属性常用的如下:

属性说明
onreadystatechangereadyState改变时调用返回函数。
readyState表示 XHR 当前状态
valuestatusdescription
0UNSET代理被创建,但未调用open()方法
1OPENED代理被创建,但未调用open()方法
2HEADERS_RECEIVEDsend()方法已经被调用,并且头部和状态已经可获得。
3LOADING下载中; responseText属性已经包含部分数据。
4DONE下载操作已完成。
status表示服务端返回的数字状态码。
response返回响应的正文。一般常用以下属性代替response
  • responseText获取服务端发送的文本数据;
  • responseXML获取服务端发送的文档数据;
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log(xhr.responseText);
} else {
console.log(xhr.response);
}
} else {
console.log('XHR request has not been completed.');
}
};

其他

AJAX 也是缺点的,比如:动态更新页面会导致用户无法回溯到 JS 处理之前的页面状态,对搜索引擎支持较弱,也可能带来别的安全问题,等等······

但是一般情况下,AJAX 带来的性能和交互上的提升远远大于其缺点。

以 AJAX 为首的技术促进了前后端分离开发的发展,也成了现代前端的基础的一部分。

AJAX 的详细介绍可以参考 MDN 文档


Fetch

The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but it provides a more powerful and flexible feature set. This article explains some of the basic concepts of the Fetch API.

从功能上来看,Fetch 与 AJAX 是相近的,并且设计和应用上更具有可扩展行和高效行,更加现代化。

Fetch 在 ES6 中添加,还是属于比较新的技术,部分浏览器的兼容性可能还不够完善,但通常来说,现代浏览器都可以完整使用。

Fetch 的最大优势在于其从设计上基于 Promise,服务于前后端分离开发,更加贴近新的 JavaScript 标准。

使用 Fetch 不需要很高的学习成本,只要你理解了 XHR,就可以很快上手。

配合 ES6 的箭头函数和 ES7 的 async/await,Fetch 使用起来简便、优雅、高效。

示例

下面的示例与前面 AJAX 功能相同,但代码更加简洁。

使用 async/await,看上去就和同步代码一样。

const fetchGetData = async () => {
const response = await fetch('/json/fetch.json');

const data = await response.json();

console.log(data);
}

发送请求

请求方式

从实际来看,现在的前后端交互消息通常为 JSON 格式。

异步 POST 请求发送 JSON 格式,请求头为 application/json;

若包含文件,则选择 application/form-data

const fetchGetText = async () => {
const response = await fetch(url);
const text = await response.text();

console.log(text);
}

异常处理

由于 Fetch 基于 Promise,所以 Fetch 可以配合 async/await 使用 .then().catch()

当然,如果你需要,也可以手动抛出异常,使用 try...catch 捕获。

try {
const response = await fetch("/404");

if (!response.ok) {
throw Error(response.statusText);
}

const json = await response.json();

console.log(json);
} catch (error) {
alert(error);
};
    fetch("/404")
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}

return response;
})

.catch((error) => {
alert(error);
})

.then((response) => response.json())

.catch((error) => {
alert(error);
});

其他

与 AJAX 相比,Fetch 还是有一些不同或者说缺陷的。

  • Fetch 对 错误的 HTTP 返回状态不会 reject。

    如:404 状态码,Fetch 并不会报错;而只有网络状态导致请求不能完成时才会报错。 这导致:对错误的返回状态,你可能需要手动抛出异常。

  • Fetch 默认不会发送 cookies,你需要手动设置。

fetch set cookies
const fetchGetWithCookies = async () => {
const response = await fetch(url, {
method: 'GET',
credentials: 'include',
});

const data = await response.json();

console.log(data);
}
  • Fetch 不支持 abort,不支持超时控制

    根据 MDN 文档的描述,该功能正在实现,或许马上就能使用了。

Fetch 的详细介绍可以参考 MDN 文档

Fetch 作为比较新的 API,随着不断更新,兼容性已经逐渐完善,功能也日益丰富。

我个人非常期待 Fetch 替代 AJAX,成为异步获取资源的首选。


最后

本篇用了很多 docusaurus v2 的新功能,希望能使文章内容更加易读易用。

希望你能喜欢。

缺陷也很明显,写起来已经不能是纯 MD 了,必须添加许多 JSX 代码······

这篇将近 800 行了,着实有点累😥。

如果有其他问题,可以在我的 github.io 项目的 issue 留言,欢迎提问~

感谢观看!Thank you for watching!