axios源码分析——请求流程

发表于:2018-6-26 13:33

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:mz同学x    来源:51testing软件测试网采编

#
流程
分享:
  axios就不在里介绍了,直接步入正题,先从一个最基本的get请求来分析下源码。
  axios.get('/get?name=xmz')
      .then((response)=>{
          console.log('response', response)
      })
      .catch((error)=>{
          console.log('error', error)
      })
  先从axios这个对象看,暂且认为它是一个普通的对象,加载axios文件后,直接就可以使用,所以就直接去文件里找它去~~~
  找到axios/lib/axios.js就直接看到了var axios躺在哪里。
  var axios = createInstance(defaults);
  先不管defaults就当是一个默认的对象,向上看就看到了createInstance方法
  function createInstance(defaultConfig){
      var context = new Axios(defaultConfig);
      //new Axios()这么说context 是一个对象了
      var instance = bind(Axios.prototype.request, context);
      //bind()要对这个对象干什么???
      //...下面的就先不看了
      return instance;
  }
  再扯远点,看看bind方法到底对context干什么了?bind定义在axios/lib/helps/bind.js这个目录下
  function bind(fn, thisArg){
      return function wrap(){
          var args = new Array(arguments.length);
              for(var i = 0; i < args.length; i++){
                  args[i] = arguments[i]
              }
              return fn.apply(thisArg, args)
          }
      }
  bind返回一个函数wrap,暂且不看里面得话,我们就可以知道instance是一个函数,那么当instance执行的时候,其实就是执行Axios.proptotype.request,this指向context,说白了bind就是改变了this指向嘛,createInstance函数返回就是这个instance,所以axios就是instance,就是一个函数。
  既然axios是一个函数,那么这个函数的get属性在哪定义的呢?然后我就在整个axios/lib文件夹下简单粗暴地搜了下axios.get,然而并没有找到~~~
  找了半天没找到啊!!抓狂!!但是在来回翻源码的时候看到Axios.prototype上有get属性,但是axios却不是Axios的实例化对象啊,怎么办?
  此时发现在var axios之后,axios马上就已经有get属性了(写了个for in 循环偷偷看了下),那么就顺着向上找把,还是找到了createInstance方法
  function createInstance(){
      //...
      //刚才有两行省略掉没看 好后悔!
      //看到extend 好激动
      utils.extend(instance, Axios.prototype, context);
      utils.extend(instance, context)
      return instance
  }
  这下知道了,axios的get属性原来是从Axios.prototype上继承来的,那就去看看utils.entend是怎么工作的吧!进入了axios/lib/util.js文件。
  function extend(a, b, thisArg){
      // extend就是把b的属性都复制个a
      forEach(b, function(value, key){
          //如果属性的值是一个方法的话,就改变this的指向到thisArg再复制给a 
          if(thisArg && typeof value == 'function'){
              a[key] = bind(val, thisArg)
          }else{
              a[key] = value;
          }
      })
      return a
  }
  axios继承了Axios.prototype和context的所有的属性,属性值是方法的话,里面的this都是指向context的。
  这回就可以去看Axios.prototype.get了,不去搜了,我看到它不是直接定义的了!哈哈哈!在axios/lib/core/Axios.js里
  utils.forEach(['delete', 'get', 'head', 'option'], function(method){
      Axios.proptotype[method] = function(url, config){
          // 先不去看util.merge了,我猜也就是把config 和 后面的对象进行下合并
          return this.request(util.merge(config||{}, {
              method: method,
              url: url
          }))
      }
  })
  Axios.prototype.get()其实去执行的是Axios.prototype.request(),还在这个文件里,向上看
  Axios.prototype.request = function request(config){
      // ...
      // 开始就对config进行判断,合并默认配置
      var chain = [dispatchRequest, undefined]
      // dispatchRequest是什么一会再说
      var promise = Promise.resolve(config)
      // Promise.resolve一个对象,promise就是一个立即resolve的Promise对象
      // ...
      // 关于interceptors拦截器的东西先不看了
      while(chain.length){
          promise = promise.then(chain.shift(), chain.shift())
      }
      return promise
  } 
  返回的是一个promise这就和axios.get('/get?name=xmz').then().catch()对上了。暂且不考虑拦截器,经过这个while循环其实就是去执行了dispatchRequest(config),那么就去axios/lib/core/dispatchRequest.js看下吧
  function dispatchRequest(config){
      // ...
      // 开始就对config的 baseUrl, data, headers进行处理  
      var adapter = config.adapter || defaults.adapter;
      // 这个adapter是什么?一路以来并没有关注啊?
      // 执行adapter是一个Promise对象,resolve的函数的参数还是response
      // adpater肯定是去发送请求了啊
      return adapter(config).then(function(response){
          // ...
          return response
      }, function(reason){
          // ...
          return Promise.reject(reason)
      })
  }
  既然config.adapter没看见,就去axios/lib/default.js看defaults.adapter吧
  var defaults.adapter = getDefaultAdapter();
  function getDefaultAdapter(){
      var adapter;
      if(typeof XMLHttpRequest !== 'undefined'){
          // 浏览器环境
          adapter = require('./adapter/xhr');
      }else if(typeof process !== 'undefined'){
          // node环境
          adapter = require('./adapter/http');
      }
      return adapter;
  }
  adapter是区分浏览器和node环境的,那么我们就去axios/lib/adapter/xhr.js看下浏览器环境的吧,就是封装了一个promise进行ajax请求服务器,就先不在这里看了。
  至此回过头来再看开始那个get请求,axios.get继承于Axios.prototype.get,其实就是去执行Axios.prototype.request,返回一个promsie对象,所以可以使用then和catch接收返回值和处理错误。进行ajax请求的主要函数就是adapter,adapter区分了一下浏览器和node环境。
  好了,忽略了各种细节,整个流程挺清楚的了!
  小白第一次分析源码,各位凑合看吧!



上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
100家互联网大公司java笔试题汇总,填问卷领取~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号