AJAX、Fetch、axios

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);   //响应主体}
}
  1. 创建AJAX实例:let xhr = new XMLHttpRequest()
  2. 打开请求,配置请求前的配置项:xhr.open([http method], [url], [async], [userName], [userPass])
    • http methods 请求方式:postgetdeleteputheadoptionstraceconnect
    • url:想服务器请求的路径
    • async:是否为异步请求
    • userNameuserPass:用户名与密码
  3. 通过XMLHttpRequest.open()方法与服务器建立连接
  4. 发送请求:XMLHttpRequest.send() 方法中如果 Ajax 请求是异步的则这个方法发送请求后就会返回,如果Ajax请求是同步的,那么请求必须知道响应后才会返回。
  5. 通过XMLHttpRequest对象的onreadystatechange事件监听服务器端的通信状态
  6. 接收数据并进行处理
  7. 将处理后的结果更新到页面上

AJAX的缺点:

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

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

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

axios的特点

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

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

  1. axios.get(url[, config]):get请求用于列表和信息查询
axios.get('apiURL', {param: {id: 1}// param 中的的键值对最终会 ? 的形式,拼接到请求的链接上,发送到服务器。
}).then(res => {console.log(res);
})
.catch( error => {console.log(error)
}
  1. axios.delete(url[, config]):删除
axios.delete('apiURL', {params: {id: 1},timeout: 1000
})
  1. axios.post(url[, data[, config]]):post请求用于信息的添加
axios.post('apiURL',{user: '小新',age: 18
}).then( res => {console.log(res);
})
.catch( error => {console.log(error)
}
  1. axios.put(url[, data[, config]]):更新操作
axios.put('apiURL', {name: '小新',
})
  1. axios.patch(url[, data[, config]]):更新操作
axios.patch('apiURL', {id: 13,
},{timeout: 1000,
})

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

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

axios相关配置

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

axios拦截器执行顺序问题

  • 请求拦截: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的链式调用将这些部分结合起来了,这样就得到了发送请求拿到数据的全部过程。

下面分析源码:

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

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

优点:

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

缺点:

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

Fetch、ajax与axios的区别

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

Fetch和Ajax比有什么优点

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

总结

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

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

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

axios源码分析

axios的执行流程

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

入口文件(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 指向 contextutils.extend(instance, Axios.prototype, context);// Axios 属性值挂载到新的实例 instance 上// 开发中才能使用 axios.default/interceptorsutils.extend(instance, context);return instance;
}

createInstance执行流程:

  1. 通过构造函数Axios创建实例context,作为下面request方法的上下文(this指向)
  2. Axios.prototype.request方法作为实例使用,并把this指向context,形成新的实例instance
  3. 将构造函数Axios.prototype上的方法挂载到新的实例instance上,然后将原型各个方法中的this指向context,这样才能使用get、post等方法
  4. Axios的属性挂载到instance

可以看到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主要做了以下操作:

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

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

总结

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

ajax、fetch和axios的比较相关推荐

  1. 理解 ajax、fetch和axios

    背景 ajax fetch.axios 优缺点 ajax基于jquery,引入时需要引入庞大的jquery库,不符合当下前端框架,于是fetch替代了ajax 由于fetch是比较底层,需要我们再次封 ...

  2. [vue] ajax、fetch、axios这三都有什么区别?

    [vue] ajax.fetch.axios这三都有什么区别? ajax, 实际上就是xmlHttpRequest, 旧瓶装新酒的一种新应用的称呼 fetch是新出的规范, 具体实现原理不太清楚, 但 ...

  3. 2021前端面试题系列:fetch与axios、浏览器内多个标签页面通信及安全问题

    大家好,我是前端岚枫,今天主要跟大家分享我整理的笔记2021前端面试题系列:fetch与axios.浏览器内标签页之间的通讯方法.XSS 和CSRF以及如何防范,此方面内容在我们的工作中常用到, 也是 ...

  4. 前端基础:vue(四)前后端交互promis、fetch、axios

    接口调用方式 原生ajax 基于jQuery的ajax fetch axios URL格式地址 格式:schema://host:port/path?query#fragment schema:协议. ...

  5. vue之购物车案例升级版、v-model之lazy、number、trim的使用、fetch和axios、计算属性、Mixins、虚拟dom与diff算法 key的作用及组件化开发

    文章目录 1.购物车案例升级版(含价格统计.全选/反选.商品增加减少) 2.v-model之lazy.number.trim的使用 3.fetch和axios 3.1.通过jquery+ajax实现v ...

  6. [js] fetch和axios请求的原理都是基于XMLHttpRerequst吗?

    [js] fetch和axios请求的原理都是基于XMLHttpRerequst吗? axios是基于XMLHttpRequest的封装,而fetch是js原生支持的网络请求api,这在浏览器底层进行 ...

  7. axios vue 回调函数_vue中ajax请求与axios包完美处理

    这次给大家带来vue中ajax请求与axios包完美处理,vue中ajax请求与axios包处理的注意事项有哪些,下面就是实战案例,一起来看一下. 在vue中,经常会用到数据请求,常用的有:vue-r ...

  8. ios ajax报错404,ajax 报错 axios正确

    ajax 报错 axios正确 [2021-01-28 03:39:02]  简介: php去除nbsp的方法:首先创建一个PHP代码示例文件:然后通过"preg_replace(" ...

  9. 怎么中断一个ajax请求,ajax、fetch、axios如何中断请求?

    先来说一说"中断请求"的实际场景,当页面有多个tab页签时,每次切换页签都会去请求数据,频繁的切换就会去请求很多次,比如A页签切换到B页签,A页签请求完全是不必要的,这时候可以在切 ...

最新文章

  1. java简体(繁体)转换器
  2. 关于Redux的一些总结(一):Action 中间件 异步
  3. 你真的懂用户画像吗?
  4. python网站开发实例视频_Python实战-让在职教育类网站的视频全自动播放
  5. 各种说明方法的答题格式_高中化学:选择题答题方法与知识点总结,让你轻松秒杀各种难题...
  6. EasyOffice-.NetCore一行代码导入导出Excel,生成Word
  7. WordPress架构简单剖析
  8. 正则表达式的三种模式【贪婪、勉强、侵占】的分析
  9. Visual studio 2012 创建web service
  10. ios 应用程序证书安装以及发布
  11. poj 2870 Light Up(dfs+剪枝,写的稀烂)
  12. .NET+Oracle 9i时产生的未在本地计算机上注册“OraOLEDB.Oracle.1”提供程序
  13. java中继承applet类_Java - 33 Java Applet基础
  14. Java 两个日期间的天数计算
  15. studio 和mac快捷键
  16. 拉取maven项目如何跑起来
  17. truffle unbox metacoin出现read ECONNRESET、ETIMEOUT、getaddrinfo ENOENT raw.githubusercontent.com问题
  18. 歌单详情内容-图标列表 (音乐app项目-第7步)
  19. Windows 计算机上查看 DNS 缓存的方法
  20. centos7 主从dns配置 bind服务

热门文章

  1. 域名国家工程研究中心再次成功入围央采
  2. powershell获取exe文件返回值
  3. 逻辑题:天涯海角猜硬币
  4. crm对于企业的重要性
  5. 战胜切尔西的N种战术设计——欧冠前献给穆帅和国米兄弟的一份技术报告
  6. [OpenGL]OpenGL几何变换的秘密(模型变换、视点变换、全局变换、局部变换)
  7. 分享 19 个免费好用的 CSS 代码样式生成器工具
  8. ZZULIOJ:1171:加密
  9. java中xsl用法_XSL-FO 简单使用方法(java xsl-fo xml)
  10. Linux学习笔记(1)-初识终端(打开终端快捷方式)