前言:
最近在研究React这个框架,成功的成为了一名新的入坑着。用过React的都知道React的强大主要是在于它的生态的强大,React说的再大不过也就是一个UI框架罢了。不过我们学习react也主要因为这个生态,有facebook支持,质量相对有保障,衍生出的react-native, react-canvas等轮子在很多场景下可以直接拿来用。碎片化是React当前的状态,比如flux库,promise库,utils函数库,dom操作库,ajax库等等,每个点都有2-3个库在开源社区处于竞争状态,各有所长,大家根据自身的需要去选择。而我打算用Fetch作为ajax库来摆脱jquery这个千年不变的大杀器。
Fetch介绍
我们一提到局部刷新,前后端交互,异步加载等首先想到的ajax,好像在我们的认知中除了ajax就没有别的了。其实我们都被这种观念误导了,ajax只是对于XMLHttpRequest的一种封装,我们谈及Ajax技术的时候,通常意思就是基于XMLHttpRequest的Ajax,它是一种能够有效改进页面通信的技术。而Fetch API则是XMLHttpRequest的最新替代技术, 它是W3C的正式标准。
Fetch的使用
下面我们看一下Fetch的兼容性
总体来说,最新的浏览器都开始慢慢的兼容它了,但是想让它独立的用于前端项目还是任重而道远啊。。。
如果你想独立在前端项目中兼容Fetch,可以考虑看这篇文章使用fetch遇到过的坑但是我不推荐去自己部署Fetch。
我是在React项目中了解到Fetch的,使用的包是:whatwg-fetch
Fetch的优点
前面说了那么多,身为吃瓜群众的我们就是好奇:那他有什么优点能让颠覆了整个前端行业的ajax退位让贤呢?
XMLHttpRequest 是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。
Fetch 的出现就是为了解决 XHR 的问题,拿例子说明:
使用 XHR 发送一个 json 请求一般是这样:
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';
xhr.onload = function() {
console.log(xhr.response);
};
xhr.onerror = function() {
console.log("Oops, error");
};
xhr.send();
使用 Fetch 后,顿时看起来好一点(其实jquery的ajax也实现了Promise)
fetch(url).then(function(response) {
return response.json();
}).then(function(data) {
console.log(data);
}).catch(function(e) {
console.log("Oops, error");
});
使用 ES6 的 箭头函数 后:
fetch(url).then(response => response.json())
.then(data => console.log(data))
.catch(e => console.log("Oops, error", e))
现在看起来好很多了,但这种 Promise 的写法还是有 Callback 的影子,而且 promise 使用 catch 方法来进行错误处理的方式有点奇怪。不用急,下面使用 async/await 来做最终优化:
注:async/await 是非常新的 API,属于 ES7,目前尚在 Stage 1(提议) 阶段,这是它的完整规范。使用 Babel 开启 runtime 模式后可以把 async/await 无痛编译成 ES5 代码。也可以直接使用 regenerator 来编译到 ES5。
try {
let response = await fetch(url);
let data = await response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e);
}
// 注:这段代码如果想运行,外面需要包一个 async function
duang~ 的一声,使用 await 后,写异步代码就像写同步代码一样爽。await 后面可以跟 Promise 对象,表示等待 Promise resolve() 才会继续向下执行,如果 Promise 被 reject() 或抛出异常则会被外面的 try...catch 捕获。
Promise,generator/yield,await/async 都是现在和未来 JS 解决异步的标准做法,可以完美搭配使用。这也是使用标准 Promise 一大好处。最近也把项目中使用第三方 Promise 库的代码全部转成标准 Promise,为以后全面
使用 async/await 做准备。
以上资料来自 传统 Ajax 已死,Fetch 永生
但是我认为Fetch最不同于ajax的是让我们对于请求头的设置更加方便,更加灵活。
Fetch中的API
对于传统的XMLHttpRequest而言,你必须使用它的一个实例来执行请求和检索返回的响应。 但是通过Fetch API,我们还能够明确的配置请求对象。你可以通过Request构造器函数创建一个新的请求对象,这也是建议标准的一部分。 第一个参数是请求的URL,第二个参数是一个选项对象,用于配置请求。请求对象一旦创建了, 你便可以将所创建 的对象传递给fetch()方法,用于替代默认的URL字符串。示例代码如下:
var req = new Request(URL, {method: 'GET', cache: 'reload'});
fetch(req).then(function(response) {
return response.json();
}).then(function(json) {
insertPhotos(json);
});
上面的代码中我们指明了请求使用的方法为GET,并且指定不缓存响应的结果。
有关Request对象的另一件更酷的事在于,你还可以基于原有的对象创建一个新的对象。 新的请求和旧的并没有什么不同,但你可以通过稍微调整配置对象,将其用于不同的场景。 例如,你可以基于原有的GET请求创建一个POST请求,它们具有相同的请求源。代码如下:
// 基于req对象创建新的postReq对象
var postReq = new Request(req, {method: 'POST'});
每个Request对象都有一个header属性,在Fetch API中它对应了一个Headers对象。 通过Headers对象,你能够修改请求头。不仅如此,对于返回的响应,你还能轻松的返回响应头中的各个属性。 但是需要注意的是,响应头是只读的。
var headers = new Headers();
headers.append('Accept', 'application/json');
var request = new Request(URL, {headers: headers});
fetch(request).then(function(response) {
console.log(response.headers);
});
在上面的代码中,你可以通过Headers构造器来获取这个对象,用于为新的Request对象配置请求头。
相似的,你可以创建一个Response对象:
function responseDemo() {
var headers = new Headers({
'Content-Type': 'application/json',
'Cache-Control': 'max-age=3600'
});
var response = new Response(
JSON.stringify({photos: {photo: []}}),
{status: 200, headers: headers}
);
response.json().then(function(json) {
insertPhotos(json);
});
}
Request和Response都完全遵循HTTP标准。
以上资料来自 深入浅出Fetch API
最后再说点
其实整合这篇文章毛目的没有,就是因为注意用post提交数据时记得设置'Content-Type'为'application/x-www-form-urlencoded; charset=UTF-8'