之前介绍 ES6 Promise 的时候就有提到一些过去的标准应该也可以更新到来支援 Promisefetch 就是个XMLHttpRequest(XHR)的 替代品,几乎是集了这几年前端领域之大成。

早已习惯Ajax的你,是否完全忽视了Fetch的入侵?究竟Fetch好在哪里了呢,我们来说道说道。

首先是命名很简单,和 XHR 完全不一样,那个时期的网路标准的命名都很繁杂,尤其像是 XML Schema 的那个时期,听说是找了些语言学家来一起制订的,那个时期的东西很多都名称弄的很冗长,当然不可否认这样有个好处是比较容易理解东西的源由,像 XHR 看名字就可以知道其实主要目的是為了抓 XML,而那个时期会想要抓 XML 大概就是为了 SOAP 协定的 Web Service 吧,只是真的用来抓 XML 的已经很少了,一直用这个名称早就已经觉得很奇怪了,至於新的 fetch 顾名思义就是为了抓东西用的,反而和现在 XHR 使用的情境很符合,而且命名很简单,好记,就像是 jQueryon取代了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目前阶段还有一些兼容性问题,但是这并不能阻挡我们的热情。毕竟一个新技术的出现总是会逐步取代老的技术。快来占领制高点,放心大胆的去尝鲜吧!

更多