当前位置:首页 > 技术分析 > 正文内容

axios中的那些天才代码!看完我实力大涨!

ruisui8813小时前技术分析2

axios的两种调用方式

经常调接口的同学一定非常熟悉aixos下面的两种使用方式:

  • axios(config)
// 配置式请求
axios({
  method: 'post',
  url: '/user/12345',
});
  • axios.post(url, config)
// 简洁的写法
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包含defaultsinterceptors属性,其对象原型__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) {
   //注意instance是函数
   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);
   //instance 是一个函数,并且可以 instance({}),

   //将Axios.prototype 对象中的方法添加到instance函数中,让instance拥有get、post、request等方法属性
   Object.keys(Axios.prototype).forEach(key => {
     // console.log(key); //修改this指向context
     instance[key] = Axios.prototype[key].bind(context);
   })
   //总结一下,到此instance自身即相当于Axios原型的request方法,
   //然后又给instance的属性添加了上了Axios原型的request、get、post方法属性
   //然后调用instance自身或instance的方法属性时,修改了this指向context这个Axios实例对象

   //为instance函数对象添加属性 default 与 intercetors
   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) {
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  if (typeof config === 'string') {
    config = arguments[1] || {};
    config.url = arguments[0];
  } else {
    config = config || {};
  }

  config = mergeConfig(this.defaults, config);

  // Set config.method
  if (config.method) {
    config.method = config.method.toLowerCase();
  } else if (this.defaults.method) {
    config.method = this.defaults.method.toLowerCase();
  } else {
    config.method = 'get';
  }

  // Hook up interceptors middleware
  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重新指向其实例化对象。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/3829.html

分享给朋友:

“axios中的那些天才代码!看完我实力大涨!” 的相关文章

快速上手React

web前端三大主流框架1、Angular大家眼里比较牛的框架,甚至有人说三大框架中只有它能称得上一个完整的框架,因为它包含的东西比较完善,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能。对于刚开始学习使用框架的小伙伴们,可以推荐这个框架,学会之后简直能颠覆之前你对前端开发的认...

2021最全VUE面试题,奥利给

1. vue-router用过没,哪些常用的钩子函数路由钩子的执行流程,钩子函数种类有:全局守卫、路由守卫、组件守卫。首页可以控制导航跳转, beforeEach , afterEach 等,?般?于页? title 的修改。?些需要登录才能调整??的重定向功能。beforeEach 主要有3个参数...

10分钟搞定gitlab-ci自动化部署

gitlab-ci 是持续集成工具/自动化部署工具,类似 jenkins。持续集成 是将代码集成到共享存储库并尽可能早地自动构建/测试每个更改的实践 - 通常一天几次。概述在编码完成时都会进行打包发布过程,如果每次都手动操作这一步骤就会浪费时间,效率低下。所以就有了持续集成。准备事项请提前安装以下软...

代码分支规范

一.gitflow工作流说明:主分支:master,稳定版本代码分支,对外可以随时编译发布的分支,不允许直接Push代码,只能请求合并(pull request),且只接受hotfix、release分支的代码合并。gitlab上做限制。热修复分支:hotfix,针对现场紧急问题、bug修复的代码分...

祸害阿里云宕机3小时的IO HANG究竟是什么?

本文来自微信公号“CSDN”(ID:CSDNnews),作者 | 王知无, 责编| 郭 芮。2019年3月3日凌晨,微博炸锅,有网友反映说阿里云疑似出现宕机,华北很多互联网公司受到暴击伤害,APP、网站全部瘫痪,我自己的朋友圈和微信群里也有好友反馈,刚刚从被窝被叫起来去修Bug,结果发现服务器登不上...

你感动了吗?佳能超规格镜头 RF 24-105mm F2.8深度测评

如果要你选一支用作多题材创作的挂机镜头,那我相信很多人会选择24-105mm这个焦段的镜头。作为一支可以实现从广角到长焦的变焦镜头,24-105mm有着丰富的焦段选择。只是基于镜头体积以及光学结构上的限制,此前的24-105mm镜头只能恒定在F4的光圈。而佳能打破了这一限制,将实用焦段和恒定光圈完美...