axios源码部分解读

最近事情多,很久没看jquery的源码了(唉),而且后面排的东西越来越多,暂时应该不会继续,下次找个机会再重新捡起来吧

因为用到的工程里包装了axios,并且还踩了次坑,所以拿来看了看

自己比较感兴趣的特性如下:

  1. 请求和返回的拦截
  2. 取消请求
  3. 请求代理

axios用到的包很少,只有url和follow-redirects,它的源码在lib文件夹下,lib下面又有adapters、cancel、core和helpers四个文件夹和axios、defaults、utils三个文件。

和有些工程不同的是,lib下面的每个目录都有readme,简要介绍了当前的文件夹是干什么用的

好了,闲话说完,看主要内容

先按大体结构来看一下:

  1. 最外层
  • axios.js是入口,主要工作是创建Axios类的实例,并扩展了一些方法
  • defaults是一些默认配置项,可以直接看git上面的注释,很齐全
  • utils里是一些工具方法
  1. core文件夹
  • core文件夹里的Axios才不到100行,主要是提供了request方法,并且把’delete’, ‘get’, ‘head’, ‘options’(不带数据)和’post’, ‘put’, ‘patch’(带数据)这几个方法绑到request上,request方法很简短,但是实现了请求和返回的拦截(通过promise.then,一个数组和数组的push、unshift方法,非常清奇)
  • dispatchRequest里处理了request data和response data的格式处理
  • 另外几个感觉没啥可说的
  1. cancel文件夹
    感觉大概是最难的了,CancelToken里有个同名构造函数和一个source函数,说实话,看了很多遍都没看懂,只理一个流程吧,先看官方给的cancel的用法,
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

流程如下:
a. 执行CancelToken里的source方法,没干啥,创建了一个CancelToken实例,传递的参数是一个函数,这个函数把自己的参数传递给了cancel这个变量,然后返回了cancel和这个CancelToken实例

CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

然后看一眼CancelToken的构造函数干了啥,创建了一个promise,把executor参数执行了一下,这个执行结果就是上面source方法里面的cancel变成了executor的参数:function cancel(message),那么后面执行source.cancel('Operation canceled by the user.');这句的时候,其实就是执行了resolvePromise(token.reason);

function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }
    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

b. a里面其实还只执行到const source = CancelToken.source();这句,接下来就是执行请求,执行请求就走到了core里的Axios.prototype.request里,比较重要的两句

...

var chain = [dispatchRequest, undefined];

... //这里会插入请求和返回的拦截器

while (chain.length) {
  promise = promise.then(chain.shift(), chain.shift());
}

排除拦截器的影响,最后会执行到dispatchRequest,dispatchRequest方法的第一句就执行了判断是否要取消请求的操作throwIfCancellationRequested(config);,这一句最终执行到

CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

抛出一个错误,结束。这是上面官方例子的取消流程,平时使用的时候,还有一种方式(同事提供),用一个变量来保存cancelToken,然后检测这个变量是否已存在,在有多次发送请求的情况下,可以取消发送过程中的请求,这样的流程和官方例子会有点不一样,因为官方例子是直接在请求前进行取消的,而这种情况会走到adapter里面去取消(在adapter文件夹中搜索cancelToken就可以找到)。
4. adapter文件夹
两种发送请求的方式,一种浏览器的ajax方式,一种是node的http方式,其中只有http方式支持请求代理,当然了,如果自己想加一个ajax方式的代理,也是可以的,模仿下代码就行了,代理其实也不是很高深的东西,只是把请求的host和port给改了,官方实例如下:

  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

上面这一段直接写在请求的配置里就可以了,不过自己手写的代理服务器的话,需要支持对应的请求路径,被这个坑了一脸,比如说,我请求http://127.0.0.1:3000/api?username=123,设置代理127.0.0.1:3001,如果3001上没有api这个路径的监听,是不会成功的

通过这次看axsios的代码,大概收获了以下这些以前没见过的知识点:

  1. URLSearchParams(兼容性不好)
  2. XDomainRequest(已经是不支持的过时的东西了)
  3. 204状态码(提交form的时候不刷新页面也不跳转)

axios前前后后大概看了得有五六回,基本都是在看请求取消的环节,非常费解,大概是水平太差,各个文件里的promise有点多也比较容易混淆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值