赞
踩
AJAX
AJAX可以在不更新全局的情况下更新局部页面。通过在与服务器进行数据交换,可以使网页实现异步更新。
AJAX的原理就是通过XHR对象来向服务器发起异步请求,从服务器获得数据,然后用JS来操作DOM更新页面。领导想找小李汇报一下工作,就委托秘书去叫小李,自己就接着做其他事情,直到秘书告诉他小李已经到了,最后小李跟领导汇报工作。Ajax请求数据流程与“领导想找小李汇报一下工作”类似,上述秘书就相当于XMLHttpRequest对象,领导相当于浏览器,响应数据相当于小李。浏览器可以发送HTTP请求后,接着做其他事情,等收到XHR返回来的数据再进行操作。
创建AJAX
// 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
,connect
url
:想服务器请求的路径async
:是否为异步请求userName
、userPass
:用户名与密码XMLHttpRequest.open()
方法与服务器建立连接XMLHttpRequest.send()
方法中如果 Ajax 请求是异步的则这个方法发送请求后就会返回,如果Ajax请求是同步的,那么请求必须知道响应后才会返回。XMLHttpRequest
对象的onreadystatechange
事件监听服务器端的通信状态AJAX的缺点:
axios原理
axios是使用promise封装的ajax,它内部有两个拦截器,分别是request拦截器和response拦截器。
axios的特点
axios常用的方法
axios常用的方法有get
、post
、put
、patch
、delete
等。其中get
和post
返回的都是promise
对象,可以使用promise
方法
axios.get(url[, config])
:get请求用于列表和信息查询axios.get('apiURL', {
param: {
id: 1
}
// param 中的的键值对最终会 ? 的形式,拼接到请求的链接上,发送到服务器。
}).then(res => {
console.log(res);
})
.catch( error => {
console.log(error)
}
axios.delete(url[, config])
:删除axios.delete('apiURL', {
params: {
id: 1
},
timeout: 1000
})
axios.post(url[, data[, config]])
:post请求用于信息的添加axios.post('apiURL',{
user: '小新',
age: 18
}).then( res => {
console.log(res);
})
.catch( error => {
console.log(error)
}
axios.put(url[, data[, config]])
:更新操作axios.put('apiURL', {
name: '小新',
})
axios.patch(url[, data[, config]])
:更新操作axios.patch('apiURL', {
id: 13,
},{
timeout: 1000,
})
put和patch的区别
patch
方法用来更新局部资源,假设我们有一个UserInfo,里面有userId,userName,userGender等10个字段。可你的编辑功能因为需求,在某个特别的页面里只能修改userName,这个时候就可以使用patch
。
put
也适用于更新数据,但必须提供完整的资源对象。
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("成功了");
为什么axios中需要拦截器
在SPA应用中,通常会使用token进行用户身份认证,这就要求每次请求必须携带用户的身份信息,针对这个需求,为了避免在每个请求中单独处理,我们可以通过封装统一的request函数来为每隔请求统一添加token信息。
但如果想为某些请求添加缓存时间或者控制某些请求的调用频率的话,我们就需要不断地修改request函数来扩展对应的功能。此时,如果在考虑对响应进行统一处理,我们的request函数将变得越来越庞大,也越来越难维护。所以axios为我们提供了拦截器。
为什么请求拦截2会在请求拦截1之前执行呢?
在axios
源码中将发送请求分为了请求拦截器、发送请求、响应拦截器、相应回调,通过Promise的链式调用将这些部分结合起来了,这样就得到了发送请求拿到数据的全部过程。
下面分析源码:
config配置对象
,用于第一次执行Promise返回一个成功的Promisechain
,这个数组中保存了请求拦截器
、响应拦截器
和发送请求函数
。该数组中间放的是发送请求的函数
,左边放的是请求拦截器
,右边放的是响应拦截器
。在第一步中返回的Promise对象,将遍历chain
数组逐一执行里面的函数,并返回新的Promise对象unshift
方法chain
中取出两个 函数执行(一个成功回调,一个失败回调)fetch
fetch
是http请求数据的方式,它使用Promise,但不使用回调函数。fetch
采用模块化设计,通过数据流处理数据,对于请求大文件或网速慢的情况相当有用。默认情况下fetch不会接收或发送cookies。
优点:
缺点:
HMLHttpRequest这个对象
,和后端进行交互。而JQury ajax
是对原生XHR
的封装,多请求间有嵌套的话就会出现回调地狱的问题。axios
使用promise
封装XHR
,解决了回调地狱的问题。Fetch
没有使用XHR
,使用的是promise
Fetch
使用的是promise
,方便使用异步,没有回调地狱的问题。
Ajax
是一种web数据交互的方式,它可以使页面在不重新加载的情况下请求数据并进行局部更新,它内部使用了XHR
来进行异步请求。Ajax
在使用XHR
发起异步请求时得到的是XML
格式的数据,如果想要JSON格式,需要进行额外的转换;Ajax
本身针对的是MVC框架
,不符合现在的MVVM架构
;Ajax
有回调地狱问题;Ajax
的配置复杂
而Fetch
是XHR的代替品,它基于Promise
实现的,并且不使用回调函数,它采用模块化结构设计,并使用数据流进行传输,对于大文件和网速慢的情况非常友好。但是Fetch
不会对请求和响应进行监听;不能阻断请求;过于底层,对一些状态码没有封装;兼容性差。
axios
是基于Promise
对XHR
进行封装,它内部封装了两个拦截器,分别是请求拦截器和响应拦截器。请求拦截器用于在请求发出之前进行一些操作,比如:设置请求体,携带Cookie、token等;响应拦截器用于在得到响应后进行一些操作,比如:登录失效后跳转到登录页面重新登录。axios
有get、post、put、patch、delete等方法。axios可以对请求和响应进行监听;返回Promise
对象,可以使用Promise
的API;返回JSON
格式的数据;由浏览器发起请求;安全性更高,可以抵御CSRF攻击。
JSON.stringify(data)
JSON.parse(data)
入口文件(lib/axios.js)
导出的axios就是 实例化后的对象,还在其上挂载create
方法,以供创建独立的实例,实现实例之间互不影响。
// 创建实例过程的方法
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; }
createInstance
执行流程:
Axios
创建实例context
,作为下面request
方法的上下文(this指向)Axios.prototype.request
方法作为实例使用,并把this
指向context
,形成新的实例instance
Axios.prototype
上的方法挂载到新的实例instance
上,然后将原型各个方法中的this
指向context
,这样才能使用get、post
等方法Axios
的属性挂载到instance
上可以看到axios不是简单的创建实例context,而是在context上进行this绑定形成新的实例,然后将Axios属性和请求方法挂载到新的实例上
拦截器(lib/core/InterceptorManager.js)
拦截器涉及一个属性和三个方法:
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主要做了以下操作:
取消请求(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.');
总结
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。