实现原生Ajax
简介
AJAX = 异步 JavaScript 和 XML。
AJAX 是一种用于创建快速动态网页的技能。
通过在后台与服务器进行少量数据互换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的环境下,对网页的某部门进行更新。
详细先容请移步AJAX 简介 | 菜鸟教程
最简版本
- function myAjax(method, url) {
- const xhr = new XMLHttpRequest()
- xhr.open(method, url)
- xhr.onreadystatechange = function () {
- if (xhr.readyState === 4) {
- if (xhr.status === 200 || xhr.status === 304) {
- console.log(xhr.responseText);
- } else {
- console.log(new Error(xhr.statusText));
- }
- }
- }
- xhr.send()
- }
复制代码 带promis版本
- function myAjax(method, url) {
- return new Promise((resolve, reject) => {
- const xhr = new XMLHttpRequest()
- xhr.open(method, url)
- xhr.onreadystatechange = function () {
- if (xhr.readyState === 4) {
- if (xhr.status === 200 || xhr.status === 304) {
- resolve(xhr.responseText)
- } else {
- resolve(new Error(xhr.statusText))
- }
- }
- }
- xhr.send()
- })
- }
复制代码 实现Axios
在平时写项目中大部门都会用到axios,但是对axios的实现却没怎么相识过,本日趁着休息,用js实现axios
简介
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它利用原生 node.js http 模块, 而在客户端 (浏览端) 则利用 XMLHttpRequests。
详细详细先容请移步起步 | Axios中文文档 | Axios中文网
这里实现出几个主要的方法,包罗post请求方法,create配置方法,以及拦截器的方法。
1.post方法
实现前先写一个类,在类的原型对象上进行方法的实现
实现时注意两点:
- axios的post的方法返回的是一个promise对象
- axios的post的方法的data参数是一个对象,而原生的XMLHttpRequest对象的send方法参数是string
所以需要在send方法里面把data参数转化为JSON格式的字符串
- cAxios.prototype.post = function (method, url, data) {
- return new Promise((resolve, reject) => {
- const xhr = new XMLHttpRequest()
- xhr.open(method, url)
- xhr.onreadystatechange = function () {
- if (xhr.readyState === 4) {
- if (xhr.status === 200 || xhr.status === 304) {
- resolve(xhr.responseText)
- } else {
- reject(new Error(reject.statusText))
- }
- }
- }
- xhr.send(JSON.stringify(data))
- })
- }
复制代码 get方法也是一样的,不再形貌
2.create方法
axios.create(config)
- 根据指定配置创建一个新的 axios, 也就就每个新 axios 都有自己的配置(主要是请求头的配置)
- 新 axios 只是没有取消请求和批量发请求的方法, 其它所有语法都是同等的
这里的实现只是列举了headers和baseUrl这两个属性
- cAxios.prototype.create = function (obj) {
- let axios = new cAxios()
- axios.headers = obj.headers;
- axios.baseUrl = obj.baseUrl;
- return axios
- }
复制代码 所以假如我们设置请求头以后,调用post方法需要带上这些参数,因此post方法需要修改
起首需要写一个方法来配置请求头
- function setHeaders(xhr, headers){
- for(let key in headers) {
- xhr.setquestHeader(key, headers[key])
- }
- }
复制代码 在post方法中,在ajax发送请求之前调用即可
- setHeaders(xhr, this.headers)
复制代码 3.拦截器
axios的拦截器分为请求拦截器和响应拦截器
寄义:在请求或响应被 then 或 catch 处理前拦截它们。
官网实例
- // 添加请求拦截器
- axios.interceptors.request.use(function (config) {
- // 在发送请求之前做些什么
- return config;
- }, function (error) {
- // 对请求错误做些什么
- return Promise.reject(error);
- });
- // 添加响应拦截器
- axios.interceptors.response.use(function (response) {
- // 2xx 范围内的状态码都会触发该函数。
- // 对响应数据做点什么
- return response;
- }, function (error) {
- // 超出 2xx 范围的状态码都会触发该函数。
- // 对响应错误做点什么
- return Promise.reject(error);
- });
复制代码 这里可以看到interceptors是一个对象,里面包含request和response属性
本文实现不考虑use
我们需要在类里面实现一下interceptors
- this.interceptors = {
- request(fn) {
- _this.saveReqFn.push(fn)
- },
- response(fn) {
- _this.saveResFn.push(fn)
- }
- }
复制代码 假如我们想在外边调用请求拦截器或者响应拦截器,需要传递一个回调函数作为拦截器的参数
所以在我们这里我们需要把这个回调函数生存下来(考虑到有多个拦截器,所以我们接纳数组生存)。
同时我们也要写一个data用于存放请求时的数据(由于在请求拦截器的回调函数中,有一个config参数,它包含着请求的数据)
- function cAxios() {
- // 保存请求拦截器中的回调函数
- this.saveReqFn = []
- // 保存响应拦截器中的回调函数
- this.saveResFn = []
- // 保存请求的数据
- this.data = []
- let _this = this
- this.interceptors = {
- request(fn) {
- _this.saveReqFn.push(fn)
- },
- response(fn) {
- _this.saveResFn.push(fn)
- }
- }
- }
复制代码 如何调用?
好比在post方法中,请求拦截器应该发送请求之前调用,响应拦截器在返回数据之前调用
- cAxios.prototype.post = function (method, url, data) {
- // 保存请求的数据
- this.data = data
- let _this = this
- // 在发送请求之前调用请求拦截器的回调函数
- if (this.saveReqFn?.length) {
- this.saveReqFn.forEach(fn => {
- fn(this)
- })
- }
- return new Promise((resolve, reject) => {
- const xhr = new XMLHttpRequest()
- xhr.open(method, url)
- setHeaders(xhr, this.headers)
- xhr.onreadystatechange = function () {
- if (xhr.readyState === 4) {
- if (xhr.status === 200 || xhr.status === 304) {
- // 创建一个新的对象,将响应的数据保存到新的对象中
- let newData = {}
- newData.data = JSON.parse(xhr.responseText)
- // 在返回数据之前调用响应拦截器的回调函数
- if (_this.saveResFn?.length) {
- _this.saveResFn.forEach(fn => {
- fn(newData)
- })
- }
- resolve(xhr.responseText)
- } else {
- reject(new Error(xhr.statusText))
- }
- }
- }
- xhr.send(JSON.stringify(data))
- })
- }
复制代码 4.完整代码
- function cAxios() {
- // 保存请求拦截器中的回调函数
- this.saveReqFn = []
- // 保存响应拦截器中的回调函数
- this.saveResFn = []
- // 保存请求的数据
- this.data = []
- let _this = this
- this.interceptors = {
- request(fn) {
- _this.saveReqFn.push(fn)
- },
- response(fn) {
- _this.saveResFn.push(fn)
- }
- }
- }function setHeaders(xhr, headers) { for (let key in headers) { xhr.setquestHeader(key, headers[key]) }}cAxios.prototype.create = function (obj) {
- let axios = new cAxios()
- axios.headers = obj.headers;
- axios.baseUrl = obj.baseUrl;
- return axios
- }cAxios.prototype.post = function (method, url, data) { // 生存请求的数据 this.data = data let _this = this // 在发送请求之前调用请求拦截器的回调函数 if (this.saveReqFn?.length) { this.saveReqFn.forEach(fn => { fn(this) }) } return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open(method, url) setHeaders(xhr, this.headers) xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 304) { // 创建一个新的对象,将请求的数据生存到新的对象中 let newData = {} newData.data = JSON.parse(xhr.responseText) // 在返回数据之前调用响应拦截器的回调函数 if (_this.saveResFn?.length) { _this.saveResFn.forEach(fn => { fn(newData) }) } resolve(xhr.responseText) } else { reject(new Error(xhr.statusText)) } } } xhr.send(JSON.stringify(data)) })}let axios = new cAxios()export { axios}
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |