React
是一个视图层框架,用于构建用户界面。在 MVC 架构中,它仅仅负责视图部分。在实际的开发过程中,往往需要我们引入一些第三方组件,比如今天要说的AJAX API
。
Asynchronous Javascript And XML (异步的JavaScript和XML)
它并不是一种单一的技术,而是有机利用一系列交互式网页应用相关的技术所形成的结合体AJAX
是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX
可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。通过不同的方式(如 Axios
、 XMLHttpRequest
或 fetch API
)使用来进行 AJAX
请求(GET、POST、PUT和DELETE),以获取、创建、更新和删除数据。
1、对JavaScript
中 Promise
比较熟悉,可以使用 Axios。
2、可以使用 jQuery
,但不建议仅仅为了进行API调用而引入整个库。
3、喜欢使用前沿标准,可以使用 fetch API
。
axios是对原生XHR的封装。它有以下几大特性:
- 可以在node.js中使用
- 提供了并发请求的接口
- 支持Promise API
它也是对原生XHR的封装,还支持JSONP,非常方便;真的是用过的都说好。但是随着react,vue等前端框架的兴起,jquery早已不复当年之勇。很多情况下我们只需要使用ajax,但是却需要引入整个jquery,这非常的不合理,于是便有了fetch的解决方案。
fetch号称是ajax的替代品,它的API是基于Promise设计的,旧版本的浏览器不支持Promise,需要使用polyfill es6-promise。Fetch API
很简单,看文档很快就学会了。推荐 MDN Fetch 教程 和 万能的WHATWG Fetch 规范。使用fetch
之前,大家需要明确fetch
的定位:fetch
是一个 low-level 的 API,它注定不会像你习惯的 $.ajax
或是axios
等库帮你封装各种各样的功能或实现。
1. 创建一个请求的实例
使用 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();
使用 ES6 的 箭头函数 后:
fetch(url,option).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 做准备。
2. 两者参数对比
- request对象
options = {
method:
headers:
body:
credentials:
mode:
cache:
redirect:
referrer:
referrerPolicy:
integrity:
}
接口参数 | fetch | XMLHttpRequest | 默认 |
---|---|---|---|
method,headers | 请求方法,请求头 | 同样的字段可以获取 | |
body | 可以接收 Blob,ArrayBuffer,FormData,String 等多种形式的参数。 | 也可以接收这些类型的参数,但是如果在低版本的浏览器中像 Blob 就没有这种格式。所以传统的 Ajax 在这方面支持情况还取决于浏览器。 | |
credentials | omit: 请求不带任何 cookie。same-origin: 同域请求会带上 cookie。include: 无论是否跨域都会带上 cookie。 | true: 大致对应上面的 include,MDN 上描述此 flag 不止控制 cookie 还控制 authorization headers 或者 TLS client certificates。false: 大致对应上面的 omit,MDN 上描述为 false 时还控制跨域请求的 response 不能设置 cookie。 | |
mode | 可以通过设置这个标志位从发起请求阶段就阻止跨域请求。 | 没有对应的标志位,只能先发出请求然后通过检测 response 头中是否有允许跨域的字段来判断是否要阻止接收 response。 | |
cache | 控制 fetch 请求如何和 HTTP 缓存协作的 | 没有对应的字段 | |
redirect | 设置请求如果遇到重定向的返回如何响应。follow=> 跟随重定向;error=>如果 response 是重定向,则报错;manual=> 自定义行为 | 没有对应的字段 | |
referrer | 设置请求 referrer 字段的值 | 没有对应的字段 | |
referrerPolicy | Referer 头如何被设置的策略 | 没有对应的字段 | |
integrity | 设置请求的 subresource integrity | 没有对应的字段 |
- response对象
fetch(url).then(function(response) {
return response.json();
}).catch(function(e) {
console.log("Oops, error");
});
接口参数 | fetch | XMLHttpRequest | 默认 |
---|---|---|---|
response.headers | 获取响应的 HTTP 头 | 有一个 getAllResponseHeaders 方法可以获取,但是返回的是以 CRLF 分割的字符串,需要自己 parse 成对象格式 | |
response.ok | 表示请求成功,即 statsu 在 200-299 之间 | 没有对应的字段 | |
response.status , response.statusText | 状态码及状态文本信息 | 同样的字段可以获取 | |
response.redirected | 此标志位表示请求是否被重定向了 | 没有对应的字段 | |
response.type | 表示 response 的类型。basic=>常规同域响应。cors=>合法的跨域响应。error=> 网络错误。opaque=> 用"no-cors"请求去获取跨域资源的响应。 | 没有对应的字段 | |
response.url | 响应对应的 url,并且是最终的 url(在重定向后最终的url) | responseURL 可以对应这个值,但是这个字段是新功能。所以传统的 Ajax 在这方面支持情况还取决于浏览器 | |
response.arrayBuffer(), response.blob() , response.formData() | 对应类型的数据的Promise对象 | Ajax 是否能实现获取这些格式的方法,取决于浏览器是否实现了相关类 | |
response.json(), response.text() | 对应类型的数据的Promise对象 | 可以通过 XMLHttpRequest.response 或者 XMLHttpRequest.responseText 获取并 pasrse |
3. 总结一下,Fetch 优点主要有:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 同构方便,使用 isomorphic-fetch
fetch支持情况
Fetch 和标准 Promise 的不足
由于 Fetch 是典型的异步场景,所以大部分遇到的问题不是 Fetch 的,其实是 Promise 的。ES6 的 Promise 是基于 Promises/A+ 标准,为了保持 简单简洁 ,只提供极简的几个 API。如果你用过一些牛 X 的异步库,如 jQuery(不要笑) 、Q.js 或者 RSVP.js,可能会感觉 Promise 功能太少了。
没有 Deferred
Deferred 可以在创建 Promise 时可以减少一层嵌套,还有就是跨方法使用时很方便。
ECMAScript 11 年就有过 Deferred 提案,但后来没被接受。其实用 Promise 不到十行代码就能实现 Deferred:es6-deferred。现在有了 async/await,generator/yield 后,deferred 就没有使用价值了。
没有获取状态方法:isRejected,isResolved
标准 Promise 没有提供获取当前状态 rejected 或者 resolved 的方法。只允许外部传入成功或失败后的回调。我认为这其实是优点,这是一种声明式的接口,更简单。
缺少其它一些方法:always,progress,finally
always 可以通过在 then 和 catch 里重复调用方法实现。finally 也类似。progress 这种进度通知的功能还没有用过,暂不知道如何替代。
不能中断,没有 abort、terminate、onTimeout 或 cancel 方法
Fetch 和 Promise 一样,一旦发起,不能中断,也不会超时,只能等待被 resolve 或 reject。幸运的是,whatwg 目前正在尝试解决这个问题 whatwg/fetch#27
参考来源:
传统 Ajax 已死,Fetch 永生
2018-11-28
网友评论