美文网首页axios源码解析
【axios源码】config合并的方法

【axios源码】config合并的方法

作者: 可以秀但没必要 | 来源:发表于2020-01-21 03:52 被阅读0次

很多框架都涉及到一个configMerge的部分。本文主要分析axios的configMerge部分源代码,主要回答两个问题:axios如何进行configMerge以及它为什么这么做。文章最后会给出相关部分的源代码。

一、预备概念

在源码解读之前,我们先进行一些准备工作。首先我们将config分为两种:UserConfigDefaultConfigUserConfig是创建实例处理化传递的根据应用场景而变化的参数,DefaultConfig是在框架编写时默认的参数。而configMerge的目标就是合并两种config。

二、源码解读

2.1 属性分类

首先axios将它用到的所有config属性分为三类:

  1. 没有初始值,其值必须由初始化的时候指定
  2. 需要合并的属性,处理时需要将Object对象合并
  3. 普通属性,处理时如果UserConfig中有则以UserConfig为准,否则取DefaultConfig的值。这些属性其值的类型除了numberstring甚至可以为functionarray等复杂类型。
  var valueFromConfig2Keys = ['url', 'method', 'params', 'data'];
  var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy'];
  var defaultToConfig2Keys = [
    'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer',
    'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
    'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress',
    'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent',
    'httpsAgent', 'cancelToken', 'socketPath'
  ];

2.2 分别处理

对于第一类先判断在UserConfig里面属性对应的值是否存在,如果存在就拿出来。

  utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) {
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    }
  });

对于第二类属性都是需要合并的object类型,因此使用专门的函数 utils.deepMerge来合并两个object

  utils.forEach(mergeDeepPropertiesKeys, function mergeDeepProperties(prop) {
    if (utils.isObject(config2[prop])) {
      config[prop] = utils.deepMerge(config1[prop], config2[prop]);
    } else if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    } else if (utils.isObject(config1[prop])) {
      config[prop] = utils.deepMerge(config1[prop]);
    } else if (typeof config1[prop] !== 'undefined') {
      config[prop] = config1[prop];
    }
  });

对于第三类,它的处理逻辑和第二类一样。如果userConfig里面存在那么以userConfig为准,否则取默认值,只不过此时是值类型,不需要前面那么麻烦。代码如下:

  utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    } else if (typeof config1[prop] !== 'undefined') {
      config[prop] = config1[prop];
    }
  });

2.3 剩余属性补全

获取userconfig中存在但是还没有被添加到config中的属性,一一将其添加到config。

 var axiosKeys = valueFromConfig2Keys
    .concat(mergeDeepPropertiesKeys)
    .concat(defaultToConfig2Keys);

  var otherKeys = Object
    .keys(config2)
    .filter(function filterAxiosKeys(key) {
      return axiosKeys.indexOf(key) === -1;
    });

  utils.forEach(otherKeys, function otherKeysDefaultToConfig2(prop) {
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    } else if (typeof config1[prop] !== 'undefined') {
      config[prop] = config1[prop];
    }
  });

三、问题

  1. valueFromConfig2Keys 中的属性不需要单独分出来,但是这些属性具有一些特点,UserConfig中才有,因此将其单独拿出来代码更容易理解。如果将其并入defaultToConfig2Keys中也是可以的,这样仅会缩减5行代码。
  2. 这个合并过程看起来很冗余,在userconfig的基础上对其进行扩展那不是更方便?但是要求UserConfig和DefaultConfig都不变就只能这样做了,这是axios的应用场景导致的。

四、完整源码

function mergeConfig(config1, config2) {
  // eslint-disable-next-line no-param-reassign
  config2 = config2 || {};
  var config = {};

  var valueFromConfig2Keys = ['url', 'method', 'params', 'data'];
  var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy'];
  var defaultToConfig2Keys = [
    'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer',
    'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
    'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress',
    'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent',
    'httpsAgent', 'cancelToken', 'socketPath'
  ];

  utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) {
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    }
  });

  utils.forEach(mergeDeepPropertiesKeys, function mergeDeepProperties(prop) {
    if (utils.isObject(config2[prop])) {
      config[prop] = utils.deepMerge(config1[prop], config2[prop]);
    } else if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    } else if (utils.isObject(config1[prop])) {
      config[prop] = utils.deepMerge(config1[prop]);
    } else if (typeof config1[prop] !== 'undefined') {
      config[prop] = config1[prop];
    }
  });

  utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    } else if (typeof config1[prop] !== 'undefined') {
      config[prop] = config1[prop];
    }
  });

  var axiosKeys = valueFromConfig2Keys
    .concat(mergeDeepPropertiesKeys)
    .concat(defaultToConfig2Keys);

  var otherKeys = Object
    .keys(config2)
    .filter(function filterAxiosKeys(key) {
      return axiosKeys.indexOf(key) === -1;
    });

  utils.forEach(otherKeys, function otherKeysDefaultToConfig2(prop) {
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    } else if (typeof config1[prop] !== 'undefined') {
      config[prop] = config1[prop];
    }
  });

  return config;
};

相关文章

网友评论

    本文标题:【axios源码】config合并的方法

    本文链接:https://www.haomeiwen.com/subject/fqvszctx.html