一文掌握ajax、fetch和axios的区别对比(obsidian spear)这都可以

随心笔谈12个月前发布 admin
86 0



目录AJAX、Fetch、axiosAJAX创建AJAXAJAX的缺点:axios原理axios的特点axios常用的方法put和patch的区别axios相关配置axios拦截器执行顺序问题为什么axios中需要拦截器为什么请求拦截2会在请求拦截1之前执行呢?Fetch、ajax与axios的区别Fetch和Ajax比有什么优点总结axios源码分析axios的执行流程

AJAX可以在不更新全局的情况下更新局部页面。通过在与服务器进行数据交换,可以使网页实现异步更新。

AJAX的原理就是通过XHR对象来向服务器发起异步请求,从服务器获得数据,然后用JS来操作DOM更新页面。领导想找小李汇报一下工作,就委托秘书去叫小李,自己就接着做其他事情,直到秘书告诉他小李已经到了,最后小李跟领导汇报工作。Ajax请求数据流程与“领导想找小李汇报一下工作”类似,上述秘书就相当于XMLHttpRequest对象,领导相当于浏览器,响应数据相当于小李。浏览器可以发送HTTP请求后,接着做其他事情,等收到XHR返回来的数据再进行操作。

image

// 1. 创建 XMLHttpRequest 实例
let xhr=XMLHttpRequest()
// 2. 打开和服务器的连接
xhr.open(‘get’, ‘URL’)
// 3.发送
xhr.send()
// 4. 接收变化。
xhr.onreadystatechange=()=> {
if(xhr.readyState==4 && xhr.status==200){ // readyState: ajax 状态,status:http 请求状态
console.log(xhr.responseText); //响应主体
}
}

创建AJAX实例:let xhr=new XMLHttpRequest()打开请求,配置请求前的配置项:xhr.open([http method], [url], [async], [userName], [userPass])
http methods 请求方式:post,get,delete,put,head,options,trace,connecturl:想服务器请求的路径async:是否为异步请求userName、userPass:用户名与密码
通过XMLHttpRequest.open()方法与服务器建立连接发送请求:XMLHttpRequest.send() 方法中如果 Ajax 请求是异步的则这个方法发送请求后就会返回,如果Ajax请求是同步的,那么请求必须知道响应后才会返回。通过XMLHttpRequest对象的onreadystatechange事件监听服务器端的通信状态接收数据并进行处理将处理后的结果更新到页面上

本是针对MVC架构,不符合前端MVVM的浪潮基于原生的XHR开发配置和调用方式混乱

axios是使用promise封装的ajax,它内部有两个拦截器,分别是request拦截器和response拦截器。

请求拦截器的作用是在请求发送之前进行一些操作,例如在每个请求体上加入token响应拦截器的作用是接收到响应后做的一些操作,例如登录失效后需要重新登录跳转到登录页

由浏览器端发起请求,在浏览器中创建XHR支持promise API监听请求和返回更好的格式化,自动将数据转换为json数据安全性更高,可抵御CSRF攻击

axios常用的方法有、、、、等。其中和返回的都是对象,可以使用方法

:get请求用于列表和信息查询

axios.get(‘apiURL’, {
param: {
id: 1
}
// param 中的的键值对最终会 ? 的形式,拼接到请求的链接上,发送到服务器。
}).then(res=> {
console.log(res);
})
.catch( error=> {
console.log(error)
}

:删除

axios.delete(‘apiURL’, {
params: {
id: 1
},
timeout: 1000
})

:post请求用于信息的添加

axios.post(‘apiURL’,{
user: ‘小新’,
age: 18
}).then( res=> {
console.log(res);
})
.catch( error=> {
console.log(error)
}

:更新操作

axios.put(‘apiURL’, {
name: ‘小新’,
})

:更新操作

axios.patch(‘apiURL’, {
id: 13,
},{
timeout: 1000,
})

方法用来更新局部资源,假设我们有一个UserInfo,里面有userId,userName,userGender等10个字段。可你的编辑功能因为需求,在某个特别的页面里只能修改userName,这个时候就可以使用。

也适用于更新数据,但必须提供完整的资源对象。

url:用于请求服务器的urlmethod:请求方法,默认为getbaseURL:会自动加到url前面proxy:用于配置代理transformRequest:允许在服务器发送请求之前修改请求数据

请求拦截:axios的请求拦截器会先执行最后指定的回调函数,再依次向前执行响应拦截:axios的响应拦截器会先执行最先执行的回调函数,再依次向前执行

例如:

axios.interceptors.request.use(config=> {
console.log(`请求拦截1`);
return config;
});
axios.interceptors.request.use(config=> {
// 在发送请求之前做些什么
console.log(`请求拦截2`);
return config;
});

// 添加响应拦截器
axios.interceptors.response.use(response=> {
// 对响应数据做点什么
console.log(`成功的响应拦截1`);
return response.data;
});

// 添加响应拦截器
axios.interceptors.response.use(response=> {
// 对响应数据做点什么
console.log(`成功的响应拦截2`);
return response;
});

// 发送请求
axios.get(‘/posts’)
.then(response=> {
console.log(‘成功了’);
})

执行结果为

console.log(“请求拦截2”);

console.log(“请求拦截1”);

console.log(“成功的响应拦截1”);

console.log(“成功的响应拦截2”);

console.log(“成功了”);

在SPA应用中,通常会使用token进行用户身份认证,这就要求每次请求必须携带用户的身份信息,针对这个需求,为了避免在每个请求中单独处理,我们可以通过封装统一的request函数来为每隔请求统一添加token信息。

但如果想为某些请求添加缓存时间或者控制某些请求的调用频率的话,我们就需要不断地修改request函数来扩展对应的功能。此时,如果在考虑对响应进行统一处理,我们的request函数将变得越来越庞大,也越来越难维护。所以axios为我们提供了拦截器。

在源码中将发送请求分为了请求拦截器、发送请求、响应拦截器、相应回调,通过Promise的链式调用将这些部分结合起来了,这样就得到了发送请求拿到数据的全部过程。

下面分析源码:

代码开始构建了一个config配置对象,用于第一次执行Promise返回一个成功的Promise最核心的数组chain,这个数组中保存了请求拦截器、响应拦截器和发送请求函数。该数组中间放的是发送请求的函数,左边放的是请求拦截器,右边放的是响应拦截器。在第一步中返回的Promise对象,将遍历chain数组逐一执行里面的函数,并返回新的Promise对象往数组中添加请求拦截函数,依照axios请求的执行顺序,请求拦截器应该在发送请求之前执行,故应该添加在发送请求函数的前面,使用unshift方法往数组中添加响应拦截器函数,依照axios请求的执行顺序,响应拦截器应该在发送请求之后执行,故应该添加在发送请求函数的后面,所以使用的是数组的push方法Promise遍历执行,每次从chain中取出两个 函数执行(一个成功回调,一个失败回调)最后返回一个Promise对象,用于执行响应数据的回调

image

fetch是http请求数据的方式,它使用Promise,但不使用回调函数。采用模块化设计,通过数据流处理数据,对于请求大文件或网速慢的情况相当有用。默认情况下fetch不会接收或发送cookies。

优点:

采用模块化思想,将输入、输出、状态跟踪分离基于promise,返回一个promise对象

缺点:

过于底层,有很多状态码没有进行封装无法阻断请求兼容性差无法检测请求进度

传统的ajax利用的是,和后端进行交互。而是对原生的封装,多请求间有嵌套的话就会出现回调地狱的问题。使用封装,解决了回调地狱的问题。而没有使用,使用的是

使用的是,方便使用异步,没有回调地狱的问题。

image

是一种web数据交互的方式,它可以使页面在不重新加载的情况下请求数据并进行局部更新,它内部使用了来进行异步请求。在使用发起异步请求时得到的是格式的数据,如果想要JSON格式,需要进行额外的转换;本身针对的是,不符合现在的;有回调地狱问题;的配置复杂

而是XHR的代替品,它基于实现的,并且不使用回调函数,它采用模块化结构设计,并使用数据流进行传输,对于大文件和网速慢的情况非常友好。但是不会对请求和响应进行监听;不能阻断请求;过于底层,对一些状态码没有封装;兼容性差。

是基于对进行封装,它内部封装了两个拦截器,分别是请求拦截器和响应拦截器。请求拦截器用于在请求发出之前进行一些操作,比如:设置请求体,携带Cookie、token等;响应拦截器用于在得到响应后进行一些操作,比如:登录失效后跳转到登录页面重新登录。有get、post、put、patch、delete等方法。axios可以对请求和响应进行监听;返回对象,可以使用的API;返回格式的数据;由浏览器发起请求;安全性更高,可以抵御CSRF攻击。

使用axios.create创建单独的实例,或直接使用axios实例对于axios调用进入到request()中进行处理执行请求拦截器请求数据转换器,将传入的数据进行处理,比如执行适配器,判断是浏览器端还是node端,以执行不同的方法响应数据转换器,对服务器端的数据进行处理,比如执行响应拦截器,对服务器端数据进行处理,比如token失效跳转到登录页返回数据

image

入口文件(lib/axios.js)

导出的axios就是 实例化后的对象,还在其上挂载方法,以供创建独立的实例,实现实例之间互不影响。

// 创建实例过程的方法
function createInstance(defaultConfig) {
return instance;
}
// 实例化
var axios=createInstance(defaults);

// 创建独立的实例,隔离作用域
axios.create=function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// 导出实例
module.exports=axios;

createInstance()

function createInstance(defaultConfig) {
// 实例化,创建一个上下文
var context=new Axios(defaultConfig);

// 平时调用的 get/post 等等请求,底层都是调用 request 方法
// 将 request 方法的 this 指向 context(上下文),形成新的实例
var instance=bind(Axios.prototype.request, context);

// Axios.prototype 上的方法 (get/post…)挂载到新的实例 instance 上,
// 并且将原型方法中 this 指向 context
utils.extend(instance, Axios.prototype, context);

// Axios 属性值挂载到新的实例 instance 上
// 开发中才能使用 axios.default/interceptors
utils.extend(instance, context);

return instance;
}

执行流程:

通过构造函数创建实例,作为下面方法的上下文(this指向)将方法作为实例使用,并把指向,形成新的实例将构造函数上的方法挂载到新的实例上,然后将原型各个方法中的指向,这样才能使用等方法将的属性挂载到上

可以看到axios不是简单的创建实例context,而是在context上进行this绑定形成新的实例,然后将Axios属性和请求方法挂载到新的实例上

拦截器(lib/core/InterceptorManager.js)

拦截器涉及一个属性和三个方法:

handler:存放use注册的回调函数use:注册成功和失败的回调函数eject:删除注册过的函数forEach:遍历回调函数

function InterceptorManager() {
// 存放 use 注册的回调函数
this.handlers=[];
}

InterceptorManager.prototype.use=function use(fulfilled, rejected, options) {
// 注册成功和失败的回调函数
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,

});
return this.handlers.length – 1;
};

InterceptorManager.prototype.eject=function eject(id) {
// 删除注册过的函数
if (this.handlers[id]) {
this.handlers[id]=null;
}
};

InterceptorManager.prototype.forEach=function forEach(fn) {
// 遍历回调函数,一般内部使用多
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !==null) {
fn(h);
}
});
};

dispatchRequest(lib/core/dispatchRequest.js)

dispatchRequest主要做了以下操作:

transformRequest: 对 config 中的 data 进行加工,比如对 post 请求的 data 进行字符串化(JSON.stringify(data))adapter:适配器,包含浏览器端 xhr 和 node 端的 httptransformResponse: 对服务端响应的数据进行加工,比如 JSON.parse(data)

image

取消请求(lib/cancel/CancelToken.js)

var CancelToken=axios.CancelToken;
var source=CancelToken.source();
axios.get(‘/user/12345’, {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log(‘Request canceled’, thrown.message);
} else {
// 处理错误
}
});
// 取消请求(message 参数是可选的)
source.cancel(‘Operation canceled by the user.’);

CancelToken 挂载 source 方法用于创建自身实例,并且返回 {token, cancel}token 是构造函数 CancelToken 的实例,cancel 方法接收构造函数 CancelToken 内部的一个 cancel 函数,用于取消请求创建实例中,有一步是创建处于 pengding 状态的 promise,并挂在实例方法上,外部通过参数 cancelToken 将实例传递进 axios 内部,内部调用 cancelToken.promise.then 等待状态改变当外部调用方法 cancel 取消请求,pendding 状态就变为 resolve,即取消请求并且抛出 reject(message)

总结

为了支持 axios() 简洁写法,内部使用 request 函数作为新实例使用 promsie 链式调用的巧妙方法,解决顺序调用问题数据转换器方法使用数组存放,支持数据的多次传输与加工适配器通过兼容浏览器端和 node 端,对外提供统一 api取消请求这块,通过外部保留 pendding 状态,控制 promise 的执行时机

到此这篇关于一文掌握ajax、fetch和axios的区别对比的文章就介绍到这了,更多相关ajax、fetch和axios的比较内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:AJAX原理以及axios、fetch区别实例详解聊一聊数据请求中Ajax、Fetch及Axios的区别ajax、axios和fetch之间优缺点重点对比总结

© 版权声明

相关文章