每日两题
这个系列将会每日更新两题面试题,虽然我不是每题都有实力解答,但是我还是能尽我所能动用所有资源来写出最好的答案。
今天的题目只有一题,不要问为什么 doge。
Ajax, Axios, Fetch 的区别
我们先来分别了解一下每个东西。
Ajax
Ajax 是 Asynchronous JavaScropt And XML 的缩写,被译为异步的 JS 和 XML。它本身并不是一项新技术,而是一个在 2005 年被Jesse James Garrett
提出的新术语。
通过 ajax 可以在浏览器向服务器发送异步请求,最大的优势在于无刷新获取数据
。它是一种将现有的标准组合在一起使用的新方式。
尽管 Ajax 中的 “X” 代表 XML ,但由于 JSON 的许多优势,目前 JSON 的使用比 XML 更加普遍。 JSON 和 XML 都被用于在 Ajax 模型中封装数据。
异步交互的优劣
异步交互相比同步交互的优势主要具有以下几点:
- 用户操作无需像同步交互必须等待结果
- 异步交互只需与服务端交换必要的数据内容,而不是将所有数据全部更新
- 异步交互对带宽造成的压力相比同步交互更小
- 通过 ajax 实现异步交互不需要任何第三方插件,只要浏览器支持 JavaScript 语言即可
但它也存在一些问题:
- 异步交互破坏了浏览器原有的前进和后退机制
- 如果后面逻辑的执行依靠前面逻辑执行的结果的话,异步交互可能会造成问题
- ajax 实现异步交互对搜索引擎(SEO)支持较弱
- ajax 实现异步交互会引起一些 Web 安全问题,例如 SQL 注入攻击、跨站点脚本攻击等问题
涉及的技术和核心
Ajax 只是为实现异步交互的手段,不是一种技术,而是多种技术的整合。其中包含以下几种技术:
- HTML 页面
- CSS
- JavaScript
- DOM
- XML
- XMLHttpRequest 对象
实现 ajax 异步交互的核心就是XMLHttpRequest对象
,该对象为客户端提供了在客户端和服务器之间传输数据的功能。
XMLHttpRequest对象
提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。
XMLHttpRequest对象
对象最初由微软设计,随后被 Mozilla、Apple 和 Google 采纳,如今已被 W3C 组织标准化。通过该对象,可以很容易地得到一个 URL 上的资源数据。尽管名字里 XML, 但 XMLHttpRequest 对象可以得到所有类型的数据资源,并不局限于 XML 格式的数据。
实现异步交互
作为客户端的 HTML 页面需要完成以下步骤:
- 创建 Ajax 的核心对象 XMLHttpRequest 对象
- 通过该对象的
open()
方法与服务器端建立连接 - 构建请求所需的数据内容,并通过该对象的
send()
方法发送给服务器端 - 通过该对象提供的
onreadystatechange
事件监听服务器端的通信状态 - 接受并处理服务器端响应的数据结果
- 将处理结果更新到 HTML 页面中
以下只是为了实现简单的异步交互,并只介绍对应的方法,若需要了解整个 xhr 对象上的方法,请前往MDN查阅
const request = new XMLHttpRequest()
/**
* @param method 当前请求的方式
* @param url 当前请求的服务器端地址
* @param async 可选的布尔参数,表示是否异步执行操作,默认true
* @param user 可选的用户名用于认证用途,默认null
* @param password 可选的密码用于认证用途,默认null
*/
request.open(method, url, [async][, user][, password])
/**
* @param body 在xhr请求中要发送的数据体,如果不传递数据则为null
*/
request.send([body])
/**
* onreadystatechange事件用于监听服务器端的通信状态,它依靠
* XMLHttpRequest.readyState属性,该属性返回一个XMLHttpRequest
* 代理当前所处的状态,只要当前属性值被改变就会触
* onreadystatechange事件。该属性有五种状态。
*
* 值 状态 描述
* 0 UNSENT 代理被创建,但尚未调用open()
* 1 OPENED open()已被调用
* 2 HEADERS_RECEIVED send()已被调用,且头部和状态已经可获得
* 3 LOADING 正在响应
* 4 DONE 响应已完毕
*
* XMLHttpRequest.responseText属性用于接收服务器端的响应结果
*/
request.onreadystatechange = function () {}
<body>
<button id="btn">click</button>
<script>
const btn = document.getElementById('btn')
btn.addEventListener('click', function () {
const xhr = new XMLHttpRequest()
xhr.open('GET', 'https://...')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.lg(xhr.responseText)
}
}
})
</script>
</body>
交互的问题
onreadystatechange 事件的绑定位置
绑定位置不同,readyState
属性的结果不一样,上面的代码readyState
属性执行的结果为
2
3
4
如果我们修改一下位置呢?
<script>
const btn = document.getElementById('btn')
btn.addEventListener('click', function () {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
console.lg(xhr.readyState)
}
xhr.open('GET', 'https://...')
xhr.send(null)
})
</script>
结果会是:
1
2
3
4
但是我们不可能的达到状态 0,是因为我们在绑定这个之前必须完成对象的初始化。
send()的问题
如果为GET
方法的话,send()
中只能传递 null,如果需要添加请求数据的话需要添加在地址中。
open('GET', 'http://...?name=value&name2=value2')
post 请求
调用send()
前,open()
后,需要通过 XHR 对象的setRequestHeader()
方法设置请求头信息。
xhr.setRequestHeader(header, value)
// eg
xhr.setRequestHeader('Content-Type', 'application/json')
然后再在send()
中发送请求数据
Axios
Axios是通过 promise 实现对 ajax 技术的一种封装的 HTTP 库,可以用在浏览器和 node.js 中,它的特性:
- 从浏览器中创建
XMLHttpRequest
- 从 node.js 创建 http 请求
- 支持
Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
其实 axios 上并没有什么原理可将的,但是它的实现(源码)可以了解了解和一些常用方法以及特点可以熟悉一下。
之后我会查阅资料并找到并记录能详细了解 axios 的各个方面。
Fetch
Fetch
是是前端发展的一种新技术产物。Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的部分,例如请求和响应。它还提供了一个全局 fetch()
方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
这种功能以前是使用 XMLHttpRequest 实现的。Fetch 提供了一个更好的替代方法,可以很容易地被其他技术使用,例如 Service Workers。Fetch 还提供了单个逻辑位置来定义其他 HTTP 相关概念,例如 CORS 和 HTTP 的扩展。
使用 fetch 的时候需要注意:
- 当接收到一个代表错误的 HTTP 状态码时,从
fetch()
返回的 Promise 不会被标记为 reject,即使 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve(但是会将 resolve 的返回值的 ok 属性设置为 false),仅当网络故障时或请求被阻止时才会标记为 reject - 默认情况下,fetch 不会从服务器端发送或接收任何 cookies,如果站点依赖于用户 session,则会导致未经认证的请求(要发送 cookies 必须设置 credentials 选项)
Fetch 代表着更先进的技术方向,但是目前兼容性不是很好,暂时不考虑展开详细讲。
区别
通过上面的一些简单了解,在不同的技术上的区别在于 Fetch 和 XMLHttpRequest。他们的差异在于:
- fetch 使用 Promise,不使用回调函数,因此大大简化了写法,写起来更简洁
- fetch 采用模块化设计,API 分散在多个对象上(Response 对象、Request 对象、Headers 对象),更合理一些;相比之下,XMLHttpRequest 的 API 设计并不是很好,输入输出和状态都在同一个接口管理,容易写出非常混乱的代码
- fetch 通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHttpRequest 对象不支持数据流,所有的数据必须放在缓存中,不支持分块读取,必须等待全部拿到后,再一次性吐出来。
- fetch 不支持
abort
,,不支持超时控制,基于 setTimeout 及 Promise.reject 的实现的超时控制并不能阻止请求过程继续再后台运行 - fetch 没有办法原生监测请求进度,xhr 可以
- fetch 默认不会带 cookie,需要添加配置项 crendentials
- fetch 只对网络请求和请求被阻止报错
那在相同的实现方法层面上,区别就在于 ajax 和 axios 之间的区别并不大,只不过 axios 是 ajax 的封装,axios 有的 ajax 都有,ajax 有的 axios 不一定有。
他们三者的关系可以用下面的图概括: