包阅导读总结
1.
关键词:axios、调用方式、原理简析、天才想法、源码实现
2.
总结:本文主要介绍了 axios 的两种调用方式,通过手写简单的 axios 代码来理解其原理,分析了 axios 既能 `axios(config)` 又能 `axios.get()` 的天才想法及源码实现,并指出修改 `this` 指向的原因。
3.
主要内容:
– axios 的两种常见调用方式
– `axios({method: ‘post’, url: ‘/user/12345’})`
– `axios.post(‘/user/12345’)`
– 原理简析
– 创建 `Axios` 构造函数
– 在原型上添加方法,如 `request`、`get`、`post`
– 创建实例对象 `aixos`
– 天才想法
– 通过 `createInstance` 函数返回实例,使 `axios` 既能作为函数 `axios(config)` 调用,又能作为对象使用其方法如 `axios.get()`
– 源码实现
– `createInstance` 函数的详细实现
– 解释为何修改 `Axios.prototype.request` 的 `this` 指向
思维导图:
文章地址:https://juejin.cn/post/7387029190620184611
文章来源:juejin.cn
作者:石小石Orz
发布时间:2024/7/3 10:56
语言:中文
总字数:1629字
预计阅读时间:7分钟
评分:91分
标签:axios,JavaScript,HTTP 请求,源码解析,构造函数
以下为原文内容
本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com
精彩新文章:# 拿客户电脑,半小时完成轮播组件开发!被公司奖励500
axios的两种调用方式
经常调接口的同学一定非常熟悉aixos下面的两种使用方式:
axios({ method: 'post', url: '/user/12345',});
axios.post('/user/12345')
不知道各位大佬有没有思考过这样的问题:
axios到底是个什么东西?我们为什么可以使用这两种方式请求接口呢?axios是怎么设计的?
axios原理简析
为了搞明白上面的问题,我们先按照传统思路仿照axios源码实现一个简单的axios。
手写一个简单的axios
创建一个构造函数
function Axios(config){ this.defaults = config; this.interceptors = { request:{}, response:{} }}
上面的代码中,我们实现了一个基本的Axios类,但它还不具备任何功能。我们现在给它添加功能。
原型上添加方法
Axios.prototype.request = function(config){ console.log('发送Ajax 请求 type:' +config.method)}Axios.prototype.get = function(){ return this.request({method:'GET'})}Axios.prototype.post = function(){ return this.request({method: 'POST'})}
上面的代码中,我们在request属性上创建了一个通用的接口请求方法,get和post实际都调用了request,但内部传递了不同的参数,这和axios(config)、axios.post()有异曲同工之妙。
参考aixos的用法, 现在,我们需要创建实例对象
let aixos = new Axios(config)
创建后的axios包含defaults
和interceptors
属性,其对象原型__proto__
上(指向Axios的prototype)包含request、get及post方法,因此,我们现在可以使用aixos.post()
的方法模拟调用接口了。
但注意,此时aixos只是一个实例对象,不是一个函数!我们似乎也没办法做到改造代码使用aixos(config)
的形式调用接口!
aixos是如何实现的呢?
aixos中的天才想法
为了即能使用axios(config)又能使用axios.get(),axios的核心伪逻辑如下
function Axios(config){ this.defaults = config; this.interceptors = { request:{}, response:{} }}Axios.prototype.request = function(config){ console.log('发送Ajax 请求 type:' +config.method)}Axios.prototype.get = function(){ return this.request({method:'GET'})}Axios.prototype.post = function(){ return this.request({method: 'POST'})}function createInstance(config) { const instance = Axios.prototype.request; instance.get = Axios.prototype.get instance.post = Axios.prototype.post return instance; }let axios = createInstance();
通过上述的伪代码,我们可以知道axios是createInstance()函数的返回值instance。
- instance 是一个函数,因此,axios也是一个函数,可以使用axios(config);
- instance也是一个对象(js万物皆对象),其原型上有get方法和post方法,因此,我们可以使用axios.post()。
我们看看aixos的源码
aixos的源码实现
function createInstance(config) { var context = new Axios(config); var instance = Axios.prototype.request.bind(context); Object.keys(Axios.prototype).forEach(key => { instance[key] = Axios.prototype[key].bind(context); }) Object.keys(context).forEach(key => { instance[key] = context[key]; }) return instance; }
可以说,上面的代码真的写的精妙绝伦啊!
注意这里,为什么要修改this的指向
var instance = Axios.prototype.request.bind(context);
首先,requset 是Axios原型对象上的方法,其方法内部的this指向的是其实例化对象context!
Axios.prototype.request = function request(config) { if (typeof config === 'string') { config = arguments[1] || {}; config.url = arguments[0]; } else { config = config || {}; } config = mergeConfig(this.defaults, config); if (config.method) { config.method = config.method.toLowerCase(); } else if (this.defaults.method) { config.method = this.defaults.method.toLowerCase(); } else { config.method = 'get'; } var chain = [dispatchRequest, undefined]; var promise = Promise.resolve(config); this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { chain.unshift(interceptor.fulfilled, interceptor.rejected); }); this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { chain.push(interceptor.fulfilled, interceptor.rejected); }); while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); } return promise;};
因此,如果我们直接使用Axios.prototype.request()
就会出现问题,因为这事reques方法内部的this会指向错误,导致函数不能运行,因此,我们必须将this重新指向其实例化对象。