本文将会根据自己的理解,来阐述Ajax, Axios, Fetch他们之间的区别
1 、JQuery ajax
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function () {},
error: function () {}
});
Ajax是对原生XHR的封装,为了达到我们跨越的目的,增添了对JSONP的支持。经过这么多年的更新维护,不得不承认它已经很成熟,能够满足我们的基本需求,但是随着react,vue新一代框架的兴起,以及ES规范的完善,更多API的更新,它逐渐暴露了自己的不足
- 针对MVC的编程设计,不符合现在前端MVVM的趋势
- 基于原生的XHR开发,XHR本身的架构不够清晰
- JQuery较大,单纯使用ajax却要引入整个JQuery非常的不合理
- 虽然axios不支持jsonp,但是可以通过引入jsonp模块来解决
2 、Axios
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Vue2.0之后,自从尤雨溪推荐大家用axios替换JQuery ajax,Axios快速的得到大家的关注。Axios本质就是对原生XHR的封装,增加了Promise的实,符合最新的ES规范,从它的官网上可以看到它有以下几条特性:
- 从 node.js 创建 http 请求
- 支持 Promise API
- 客户端支持防止CSRF(请求中携带cookie)
- 提供了一些并发请求的接口(重要,方便了很多的操作)
Axios既提供了并发的封装,体积也较小,也没有下文会提到的fetch的各种问题,当之无愧是现在最应该选用的请求的方式。
3、 Fetch
fetch号称是AJAX的替代品,fetch是基于原生的XMLHttpRequest对象来实现数据请求的,同时也是基于Promise实现链式调用的。它的好处在《传统 Ajax 已死,Fetch 永生》中提到有以下几点:
- 符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
- 更好更方便的写法,诸如:
try {
let response = await fetch(url);
let data = await response.json();
console.log(data);
} catch(e) {
console.log("error:", e);
}
使用 await 后,告别面条式调用,将异步写成同步,身心舒畅。从上图可以看到await 后面可以跟 Promise 对象,表示等待 Promise resolve() 才会继续向下执行,如果 Promise 被 reject() 或抛出异常则会被外面的 try...catch 捕获。
坦白说,Jquery还是Axios都已经将xhr封装的足够好,使用起来也足够方便,但是Fetch还是得到很多开发者的认可,说明它还是存在很多优势的:
- 更加底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
- 跨域处理(mode为"no-cors")
fetch('/testPost', {
method: 'post',
mode: 'no-cors',
data: {}
}).then(function() {});
但是在使用fetch的时候,也会遇到了一些问题:
- fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
- fetch默认不会带cookie,需要添加配置项fetch(url, {credentials: 'include'})
- fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
- fetch没有办法原生监测请求的进度,而XHR可以
- 所有版本的 IE 均不支持原生 Fetch,fetch-ie8 会自动使用 XHR 做 polyfill。但在跨域时有个问题需要处理。IE8, 9 的 XHR 不支持 CORS 跨域,不支持传 Cookie!所以推荐使用 fetch-jsonp
PS: fetch的具体问题大家可以参考:《fetch没有你想象的那么美》《fetch使用的常见问题及解决方法》
xhr+promise的实现原理如下:
function Promise(fn) {
this.resolveFn = null;
this.rejectFn = null;
var _this = this;
function resolve(data) {
var f = _this.resolveFn;
f(data);
}
function reject(err) {
var f = this.rejectFn;
f(err);
}
fn(resolve,reject);
}
Promise.prototype.then = function (f) {
this.resolveFn = f; return this;
};
Promise.prototype.catch = function (f) {
this.rejectFn = f; return this;
};
function ajax(url,suc,fail) {
var xhr = new XMLHttpRequest();
xhr.open('GET',url, true);
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
if(xhr.status == 200){
suc(xhr.responseText)
} else {
console.log(err);
fail(xhr.responseText);
}
}
};
xhr.send(null);
}
function fetch(url) {
console.log('fetch start')
return new Promise(function (resolve,reject) {
ajax(url,function (res) {
resolve(res);
},function (err) {
console.log(err);
reject(err);
})
})
}
fetch('/test').then(function (res) {
console.log(JSON.parse(res));
}).catch (function (err) {
console.log(err);
})