话说Fetch这个API

前言:

最近在研究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遇到过的坑但是我不推荐去自己部署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'

posted @ 2017-01-16 17:27  一半水一半冰  阅读(7049)  评论(1编辑  收藏  举报
Fork me on GitHub