axios核心源码逻辑实现(一)
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
各位小伙伴们大家好,今天我们来学习一下axios的核心源码逻辑实现。axios是目前最火热的数据请求库,相对于其他的请求库,它在语法上面也做了一些简化,容易上手,内容上通俗易懂。
目标
今天我们要实现axios发送请求的基本逻辑,具体效果如下:
打印结果为:
我们先来实现如图的逻辑业务,在下一篇章我们将讲解关于发送请求相关的具体实现
实现步骤
一 创建Axios构造函数
二 在Axios原型上挂载方法
三 声明createInstance函数在内部完成相关业务
四 调用axios函数
具体功能实现
一 创建Axios构造函数
首先我们需要创建一个axios的构造函数,它的内部要实现在其实例化身上添加两个对象,并接受传递过来的config参数,注意这个参数会贯穿从上到下的代码业务,代码如下:
//构造函数
function Axios(config) {
//初始化
this.defaults = config;//为了创建 default 默认属性
this.intercepters = {
request: {},
response: {}
}
}
可以看到我们在其实例化对象身上添加了default属性,它的值即为config对象。我们又在其实例化对象身上添加了intercepters属性,它的值为一个对象,这个对象里又包含两个属性,request和response,其分别指向一个对象。这里的request和response与我们后面的拦截器相关内的内容有联系,在这里不多做阐述
二 在Axios原型上挂载方法
第二步我们需要在在Axios的原型上挂载一些方法,这些方法就是我们调用真正的axios请求时常会用到的方法,分别是request,get,post 代码如下:
//原型添加相关的方法
Axios.prototype.request = function (config) {
console.log('发送 AJAX 请求 请求的类型为 ' + config.method);
}
Axios.prototype.get = function (config) {
return this.request({ method: 'GET' });
}
Axios.prototype.post = function (config) {
return this.request({ method: 'POST' });
}
可以看到在这三个方法中我们都接受了一个config形参,它会用来最后反馈axios的执行结果
三 创建createInstance函数
这一步是很关键,也是我们今天的核心代码片段。在创建的createInstance函数中,我们要完成实例化对象以及forEach遍历添加属性等一些操作。
首先我们同样需要在createInstance函数中接收一个config参数,在函数体内,我们要创建一个Axios的实例化对象,并用context接收,这个context的作用就是为下面的一个变量提供this指向和为这个变量添加属性,如下
//声明函数
function createInstance(config) {
//实例化一个对象
let context = new Axios(config);// context.get() context.post() 但是不能当做函数使用 context() X
}
需要注意的是,此时new出来的context是一个对象,不能完成get和post的请求。
接着我们需要创建一个请求函数instance,它是createInstance函数的最终返回值,这个instance函数可以被看作就是Axios.prototype.request请求函数,但需要改变其内部指向为context,如下
//声明函数
function createInstance(config) {
//实例化一个对象
let context = new Axios(config);// context.get() context.post() 但是不能当做函数使用 context() X
//创建请求函数
let instance = Axios.prototype.request.bind(context);// instance 是一个函数 并且可以 instance({}) 此时 instance 不能 instance.get X
console.dir(instance);
}
这里调用的bind函数,返回了一个新的函数instance,bind函数内部的context也完成了新函数instance内部的this指向覆盖
然后我们需要将构造函数Axios原型上添加的几种方法依次添加给instance这个复杂数据类型。
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context);// this.default this.interceptors
});
这里解释一下,Object.key( )可以用来遍历对象里面的属性,因此这里遍历了Axios原型上添加的一些方法,并利用forEach函数依次循环为instance添加方法。
当然,我们也需要为instance函数添加属性default 与 interceptors,同样的,步骤大致与上面一样,createInstance函数完整代码如下:
//声明函数
function createInstance(config) {
//实例化一个对象
let context = new Axios(config);// context.get() context.post() 但是不能当做函数使用 context() X
//创建请求函数
let instance = Axios.prototype.request.bind(context);// instance 是一个函数 并且可以 instance({}) 此时 instance 不能 instance.get X
console.dir(instance);
//将 Axios.prototype 对象中的方法添加到instance函数对象中
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context);// this.default this.interceptors
});
//为 instance 函数对象添加属性 default 与 interceptors
Object.keys(context).forEach(key => {
instance[key] = context[key];
});
//打印 instance函数 的身上的方法和属性
console.dir(instance)
return instance;
}
打印结果如下:
可以看到instance函数身上多了一些我们刚才给它添加的属性和方法,并最终将其返回
四 调用axios函数
最后一步我们调用createInstance函数,将其执行结果赋值给新变量axios,此时这个axios就是createInstance函数的执行结果instance,我们就可以调用它身上的属性和方法了
代码如下
let axios = createInstance();
//发送请求
axios({method:'POST'});
axios.get({});
axios.post({});
执行结果如图:
总结
这节课我们完成了axios发送请求的基本逻辑,各位小伙伴们要在自己手写时多调试,多打印对象身上的属性和方法,分析什么时候会发生变化以及发生了哪些变化,在后面的文章中我们需要大量的涉及到promise函数,请各位先将promise的源码复习一遍
本节代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> axios 的由来</title>
</head>
<body>
<script>
// console.log(axios);
// axios();
// axios.get();
// axios.post();
//构造函数
function Axios(config) {
//初始化
this.defaults = config;//为了创建 default 默认属性
this.intercepters = {
request: {},
response: {}
}
}
//原型添加相关的方法
Axios.prototype.request = function (config) {
console.log('发送 AJAX 请求 请求的类型为 ' + config.method);
}
Axios.prototype.get = function (config) {
return this.request({ method: 'GET' });
}
Axios.prototype.post = function (config) {
return this.request({ method: 'POST' });
}
//声明函数
function createInstance(config) {
//实例化一个对象
let context = new Axios(config);// context.get() context.post() 但是不能当做函数使用 context() X
//创建请求函数
let instance = Axios.prototype.request.bind(context);// instance 是一个函数 并且可以 instance({}) 此时 instance 不能 instance.get X
//将 Axios.prototype 对象中的方法添加到instance函数对象中
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context);// this.default this.interceptors
});
//为 instance 函数对象添加属性 default 与 interceptors
Object.keys(context).forEach(key => {
instance[key] = context[key];
});
// console.dir(instance)
return instance;
}
let axios = createInstance();
//发送请求
axios({method:'POST'});
axios.get({});
axios.post({});
</script>
</body>
</html>