XHR ! Fetch API?
之前介绍 ES6 Promise 的时候就有提到一些过去的标准应该也可以更新到来支援 Promise
,fetch
就是个XMLHttpRequest
(XHR)的 替代品,几乎是集了这几年前端领域之大成。
早已习惯Ajax的你,是否完全忽视了Fetch的入侵?究竟Fetch好在哪里了呢,我们来说道说道。
首先是命名很简单,和 XHR
完全不一样,那个时期的网路标准的命名都很繁杂,尤其像是 XML Schema
的那个时期,听说是找了些语言学家来一起制订的,那个时期的东西很多都名称弄的很冗长,当然不可否认这样有个好处是比较容易理解东西的源由,像 XHR
看名字就可以知道其实主要目的是為了抓 XML,而那个时期会想要抓 XML 大概就是为了 SOAP
协定的 Web Service
吧,只是真的用来抓 XML 的已经很少了,一直用这个名称早就已经觉得很奇怪了,至於新的 fetch
顾名思义就是为了抓东西用的,反而和现在 XHR
使用的情境很符合,而且命名很简单,好记,就像是 jQuery
的on
取代了addEventListener
一样。
以前我们用 jQuery.ajax 发一个请求是这样的:
$.ajax('/').then(function(res){
console.log(res)
})
现在我们用 fetch 发一个请求是这样的:
fetch('/').then(function(res){
res().then(function(text){
console.log(text)
})
})
是不是感觉很像,像就对了,因为 Fetch API 就是浏览器提供的用来代替 jQuery.ajax 的工具。
XMLHttpRequest
是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。
先学习下Fetch
自定义的请求头会让Fetch使用起来更加灵活,我们通过new Headers()来创建:
// Create an empty Headers instance
var headers = new Headers();
// Add a few headers
headers.append('Content-Type', 'text/plain');
headers.append('X-My-Custom-Header', 'CustomValue');
// Check, get, and set header values
headers.has('Content-Type'); // true
headers.get('Content-Type'); // "text/plain"
headers.set('Content-Type', 'application/json');
// Delete a header
headers.delete('X-My-Custom-Header');
// Add initial values
var headers = new Headers({
'Content-Type': 'text/plain',
'X-My-Custom-Header': 'CustomValue'
});
如果需要修改请求头,我们先得创建一个Request实例,如下:
const request = new Request('http://jartto.wang/test.json', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
})
});
fetch(request).then(function() { /* handle response */ });
到这里,请求头也设置完了,那么我们来看看Request和Response吧。
Request和Response
Request也就是一次Fetch调用的请求信息,其实上面已经提到了,这里我们采用简写方式:
fetch('http://jartto.wang/test.json', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
})
}).then(function() { /* handle response */ });
Request 参数说明:
- method - GET, POST, PUT, DELETE, HEAD
- url - 请求的url
- headers - 对应的Header对象
- referrer - 请求的referrer信息
- mode - 模式,可选类型有cors, no-cors, same-origin
- credentials - 是否携带cookie,可选类型有omit, same-origin
- redirect - follow, error, manual
- integrity - subresource integrity value
- cache - 缓存模式,可选类型有default, reload, no-cache
相比之下,Response就稍微简单了,Fetch的then方法接收了一个Response实例。当然,你也可以自己去创建Response对象,然后去修改它。
// new Response(BODY, OPTIONS)
var response = new Response('.....', {
ok: false,
status: 404,
url: '/'
});
// The fetch's `then` gets a Response instance back
fetch('http://jartto.wang/')
.then(function(responseObj) {
console.log('status: ', responseObj.status);
});
Response 参数说明:
- type - 类型,支持basic, cors
- url
- useFinalURL - 是否是最终的url,Boolean类型
- status - 状态码 (200, 404,等)
- ok - Boolean值,代表成功响应(status值在200-299之间)
- statusText - 状态值(例如:OK)
- headers - 与响应相关联的Headers对象
此外,Response还提供了如下的方法:
- clone() - 创建一个新的Response克隆对象
- error() - 返回一个新的,与网络错误相关的Response对象
- redirect() - 重定向,使用新的URL创建新的Response对象
- arrayBuffer() - 返回一个promise,resolves是一个ArrayBuffer
- blob() - 返回一个promise,resolves是一个Blob
- formData() - 返回一个promise, resolves是一个FormData对象
- json() - 返回一个promise,resolves是一个JSON对象
- text() - 返回一个promise,resolves是一个USVString(text)
Fetch API 的特点
基于 Promise(如果你没有学过 Promise,强烈建议你学一学) 不需要依赖第三方库,就可以优雅地使用 AJAX
Fetch API 的问题
使用 fetch 无法取消一个请求。Ajax调用XMLHttpRequest对象上的abort方法,但是Fetch好像没啥办法。这是因为 Fetch API 基于 Promise,而 Promise 无法做到这一点。不过相信很快就会有对策。
兼容性
有的浏览器没有 Fetch API,没有关系,只要引入一个 polyfill 就可以了:GitHub - github/fetch: A window.fetch JavaScript polyfill.
可以看到fetch目前阶段还有一些兼容性问题,但是这并不能阻挡我们的热情。毕竟一个新技术的出现总是会逐步取代老的技术。快来占领制高点,放心大胆的去尝鲜吧!