手写axios核心原理,再也不怕面试官问我axios原理,2024年最新CSS外边距塌陷问题

}

})

// 工具方法,实现b的方法或属性混入a;

// 方法也要混入进去

const utils = {

extend(a,b, context) {

for(let key in b) {

if (b.hasOwnProperty(key)) {

if (typeof b[key] === ‘function’) {

a[key] = b[key].bind(context);

} else {

a[key] = b[key]

}

}

}

}

}

// 最终导出axios的方法-》即实例的request方法

function CreateAxiosFn() {

let axios = new Axios();

let req = axios.request.bind(axios);

// 混入方法, 处理axios的request方法,使之拥有get,post…方法

utils.extend(req, Axios.prototype, axios)

return req;

}

// 得到最后的全局变量axios

let axios = CreateAxiosFn();

四、请求和响应拦截器


我们先看下拦截器的使用

// 添加请求拦截器

axios.interceptors.request.use(function (config) {

// 在发送请求之前做些什么

return config;

}, function (error) {

// 对请求错误做些什么

return Promise.reject(error);

});

// 添加响应拦截器

axios.interceptors.response.use(function (response) {

// 对响应数据做点什么

return response;

}, function (error) {

// 对响应错误做点什么

return Promise.reject(error);

});

拦截器是什么意思呢?其实就是在我们发送一个请求的时候会先执行请求拦截器的代码,然后再真正地执行我们发送的请求,这个过程会对config,也就是我们发送请求时传送的参数进行一些操作。

而当接收响应的时候,会先执行响应拦截器的代码,然后再把响应的数据返回来,这个过程会对response,也就是响应的数据进行一系列操作。

怎么实现呢?需要明确的是拦截器也是一个类,管理响应和请求。因此我们先实现拦截器

class InterceptorsManage {

constructor() {

this.handlers = [];

}

use(fullfield, rejected) {

this.handlers.push({

fullfield,

rejected

})

}

}

我们是用这个语句axios.interceptors.response.useaxios.interceptors.request.use,来触发拦截器执行use方法的。

说明axios上有一个响应拦截器和一个请求拦截器。那怎么实现Axios呢?看代码

class Axios {

constructor() {

新增代码

this.interceptors = {

request: new InterceptorsManage,

response: new InterceptorsManage

}

}

request(config) {

return new Promise(resolve => {

const {url = ‘’, method = ‘get’, data = {}} = config;

// 发送ajax请求

console.log(config);

const xhr = new XMLHttpRequest();

xhr.open(method, url, true);

xhr.onload = function() {

console.log(xhr.responseText)

resolve(xhr.responseText);

};

xhr.send(data);

})

}

}

可见,axios实例上有一个对象interceptors。这个对象有两个拦截器,一个用来处理请求,一个用来处理响应。

所以,我们执行语句axios.interceptors.response.useaxios.interceptors.request.use的时候,实现获取axios实例上的interceptors对象,然后再获取response或request拦截器,再执行对应的拦截器的use方法。

而执行use方法,会把我们传入的回调函数push到拦截器的handlers数组里。

到这里你有没有发现一个问题。这个interceptors对象是Axios上的啊,我们导出的是request方法啊(欸?好熟悉的问题,上面提到过哈哈哈~~~额)。处理方法跟上面处理的方式一样,都是把Axios上的方法和属性搬到request过去,也就是遍历Axios实例上的方法,得以将interceptors对象挂载到request上。

所以只要更改下CreateAxiosFn方法即可。

function CreateAxiosFn() {

let axios = new Axios();

let req = axios.request.bind(axios);

// 混入方法, 处理axios的request方法,使之拥有get,post…方法

utils.extend(req, Axios.prototype, axios)

新增代码

utils.extend(req, axios)

return req;

}

好了,现在request也有了interceptors对象,那么什么时候拿interceptors对象中的handler之前保存的回调函数出来执行。

没错,就是我们发送请求的时候,会先获取request拦截器的handlers的方法来执行。再执行我们发送的请求,然后获取response拦截器的handlers的方法来执行。

因此,我们要修改之前所写的request方法 之前是这样的。

request(config) {

return new Promise(resolve => {

const {url = ‘’, method = ‘get’, data = {}} = config;

// 发送ajax请求

console.log(config);

const xhr = new XMLHttpRequest();

xhr.open(method, url, true);

xhr.onload = function() {

console.log(xhr.responseText)

resolve(xhr.responseText);

};

xhr.send(data);

})

}

但是现在request里不仅要执行发送ajax请求,还要执行拦截器handlers中的回调函数。所以,最好下就是将执行ajax的请求封装成一个方法

request(config) {

this.sendAjax(config)

}

sendAjax(config){

return new Promise(resolve => {

const {url = ‘’, method = ‘get’, data = {}} = config;

// 发送ajax请求

console.log(config);

const xhr = new XMLHttpRequest();

xhr.open(method, url, true);

xhr.onload = function() {

console.log(xhr.responseText)

resolve(xhr.responseText);

};

xhr.send(data);

})

}

好了,现在我们要获得handlers中的回调

request(config) {

// 拦截器和请求组装队列

let chain = [this.sendAjax.bind(this), undefined] // 成对出现的,失败回调暂时不处理

// 请求拦截

this.interceptors.request.handlers.forEach(interceptor => {

chain.unshift(interceptor.fullfield, interceptor.rejected)

})

// 响应拦截

this.interceptors.response.handlers.forEach(interceptor => {

chain.push(interceptor.fullfield, interceptor.rejected)

})

// 执行队列,每次执行一对,并给promise赋最新的值

let promise = Promise.resolve(config);

while(chain.length > 0) {

promise = promise.then(chain.shift(), chain.shift())

}

return promise;

}

我们先把sendAjax请求和undefined放进了chain数组里,再把请求拦截器的handlers的成对回调放到chain数组头部。再把响应拦截器的handlers的承兑回调反倒chain数组的尾部。

然后再 逐渐取数 chain数组的成对回调执行。

promise = promise.then(chain.shift(), chain.shift())

这一句,实际上就是不断将config从上一个promise传递到下一个promise,期间可能回调config做出一些修改。什么意思?我们结合一个例子来讲解一下

首先拦截器是这样使用的

// 添加请求拦截器

axios.interceptors.request.use(function (config) {

// 在发送请求之前做些什么

return config;

}, function (error) {

// 对请求错误做些什么

return Promise.reject(error);

});

// 添加响应拦截器

axios.interceptors.response.use(function (response) {

// 对响应数据做点什么

return response;

}, function (error) {

// 对响应错误做点什么

return Promise.reject(error);

});

然后执行request的时候。chain数组的数据是这样的

chain = [

function (config) {

// 在发送请求之前做些什么

return config;

},

function (error) {

// 对请求错误做些什么

return Promise.reject(error);

}

this.sendAjax.bind(this),

undefined,

function (response) {

// 对响应数据做点什么

return response;

},

function (error) {

// 对响应错误做点什么

return Promise.reject(error);

}

]

首先

执行第一次promise.then(chain.shift(), chain.shift()),即

promise.then(

function (config) {

// 在发送请求之前做些什么

return config;

},

function (error) {

// 对请求错误做些什么

return Promise.reject(error);

}

)

一般情况,promise是resolved状态,是执行成功回调的,也就是执行

function (config) {

// 在发送请求之前做些什么

return config;

},

而promise.then是要返回一个新的promise对象的。为了区分,在这里,我会把这个新的promise对象叫做第一个新的promise对象 这个第一个新的promise对象会把

function (config) {

// 在发送请求之前做些什么

return config;

},

的执行结果传入resolve函数中

resolve(config)

使得这个返回的第一个新的promise对象的状态为resovled,而且第一个新的promise对象的data为config。

这里需要对Promise的原理足够理解。所以我前一篇文章写的是手写Promise核心原理,再也不怕面试官问我Promise原理,你可以去看看

接下来,再执行

promise.then(

sendAjax(config)

,

undefined

)

注意:这里的promise是 上面提到的第一个新的promise对象。

而promise.then这个的执行又会返回第二个新的promise对象。

因为这里promise.then中的promise也就是第一个新的promise对象的状态是resolved的,所以会执行sendAjax()。而且会取出第一个新的promise对象的data 作为config转入sendAjax()。

当sendAjax执行完,就会返回一个response。这个response就会保存在第二个新的promise对象的data中。

接下来,再执行

promise.then(

function (response) {

// 对响应数据做点什么

return response;

},

function (error) {

// 对响应错误做点什么

return Promise.reject(error);

}

)

同样,会把第二个新的promise对象的data取出来作为response参数传入

function (response) {

// 对响应数据做点什么

return response;

},

饭后返回一个promise对象,这个promise对象的data保存了这个函数的执行结果,也就是返回值response。

然后通过return promise;

把这个promise返回了。咦?是怎么取出promise的data的。我们看看我们平常事怎么获得响应数据的

axios.get(‘http://localhost:5000/getTest’)

.then(res => {

console.log(‘getAxios 成功响应’, res);

})

在then里接收响应数据。所以原理跟上面一样,将返回的promise的data作为res参数了。

现在看看我们的myAxios完整代码吧,好有个全面的了解

class InterceptorsManage {

constructor() {

this.handlers = [];

}

use(fullfield, rejected) {

this.handlers.push({

fullfield,

rejected

})

}

}

class Axios {

constructor() {

this.interceptors = {

request: new InterceptorsManage,

response: new InterceptorsManage

}

}

request(config) {

// 拦截器和请求组装队列

let chain = [this.sendAjax.bind(this), undefined] // 成对出现的,失败回调暂时不处理

// 请求拦截

this.interceptors.request.handlers.forEach(interceptor => {

chain.unshift(interceptor.fullfield, interceptor.rejected)

})

// 响应拦截

this.interceptors.response.handlers.forEach(interceptor => {

chain.push(interceptor.fullfield, interceptor.rejected)

})

// 执行队列,每次执行一对,并给promise赋最新的值

let promise = Promise.resolve(config);

while(chain.length > 0) {

promise = promise.then(chain.shift(), chain.shift())

}

return promise;

}

sendAjax(){

return new Promise(resolve => {

const {url = ‘’, method = ‘get’, data = {}} = config;

// 发送ajax请求

console.log(config);

const xhr = new XMLHttpRequest();

xhr.open(method, url, true);

xhr.onload = function() {

console.log(xhr.responseText)

resolve(xhr.responseText);

};

xhr.send(data);

})

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

文末

逆水行舟不进则退,所以大家要有危机意识。

同样是干到35岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说35岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

为了帮助大家更好温习重点知识、更高效的准备面试,特别整理了《前端工程师核心知识笔记》电子稿文件。

内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

前端面试题汇总

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-uQK5mPBh-1712772330018)]

文末

逆水行舟不进则退,所以大家要有危机意识。

同样是干到35岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说35岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

为了帮助大家更好温习重点知识、更高效的准备面试,特别整理了《前端工程师核心知识笔记》电子稿文件。

内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

前端面试题汇总

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-aGQmIdBX-1712772330018)]

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Axios是一个基于Promise的HTTP客户端,用于在浏览器和Node.js中进行HTTP请求。它的底层原理涉及到几个主要的概念和步骤。 首先,Axios使用XMLHttpRequest对象(在浏览器中)或http模块(在Node.js中)来发送HTTP请求。它通过创建一个XMLHttpRequest实例或使用http模块的请求方法来进行通信。 其次,Axios允许你配置请求选项,例如请求的URL、请求方法、请求头、请求体等。你可以通过传递一个包含这些选项的配置对象来进行配置。 然后,Axios发送请求并等待服务器的响应。它使用Promise来处理异步操作,并返回一个Promise对象,该对象可以用于处理成功的响应或处理错误。 在发送请求之前,Axios还支持拦截器(interceptors)。拦截器可以在请求被发送之前或响应被处理之前对它们进行拦截和修改。你可以通过使用`axios.interceptors.request.use`方法来添加请求拦截器,使用`axios.interceptors.response.use`方法来添加响应拦截器。 当服务器响应到达时,Axios会解析响应数据并返回给调用者。它还会根据HTTP状态码将Promise解决为成功或失败。 最后,Axios提供了一些用于处理响应的方法,比如`.then`和`.catch`。你可以使用这些方法来处理成功的响应或处理错误。 总结来说,Axios的底层原理涉及到创建并配置HTTP请求、发送请求、拦截请求和响应、处理响应数据以及返回Promise对象供调用者处理。这使得Axios成为一个方便、强大且易于使用的HTTP客户端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值