从零实现axios(2.1小节-实现默认配置对象)

28 阅读2分钟

请求默认配置对象

我们完善defaults/index.js文件里的默认配置对象,我们添加 timeout 参数,该参数的作用是设置请求超时时间,还提供了 validateStatus 验证响应状态码的方法,第一章 settle 函数里面的验证方法默认使用该方法。defaults.headers 对象跟请求头有关,headers.common 对象指定了请求头的通用配置,headers.common.Accept 属性指定了要接收的响应数据类型,同时我们在 headers 对象上指定了 post, put, patch 方法的默认 Content-Type 类型为 application/x-www-form-urlencoded

var utils = require("../utils");

var DEFAULT_CONTENT_TYPE = {
  "Content-Type": "application/x-www-form-urlencoded",
};

// 获取浏览器或node环境下发http请求的adapter
// 我们只讲浏览器部分
function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== "undefined") {
    // 用于发起浏览器xhr请求
    adapter = require("../adapters/xhr");
  }
  return adapter;
}

var defaults = {
  adapter: getDefaultAdapter(),
  /**
   * 请求的超时时间. 设为 0 表示没有超时限制
   *
   */
  timeout: 0,

  // 验证响应状态码
  validateStatus: function validateStatus(status) {
    return status >= 200 && status < 300;
  },
};

defaults.headers = {
  common: {
    Accept: "application/json, text/plain, */*",
  },
};

// 没有数据的方法
utils.forEach(["delete", "get", "head"], function forEachMethodNoData(method) {
  defaults.headers[method] = {};
});

// 有数据的方法,需要指定Content-Type
utils.forEach(["post", "put", "patch"], function forEachMethodWithData(method) {
  // 通过merge方法,每个方法得到一个不同的对象,且该对象包含DEFAULT_CONTENT_TYPE的内容
  defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});

module.exports = defaults;

我们在utils.js 中来实现 merge 辅助函数

var toString = Object.prototype.toString;

// Object.create(null)创建一个缓存对象,是为了优化性能
var kindOf = (function(cache) {
  return function(thing) {
    var str = toString.call(thing);
    // str的格式为'[object type]',str.slice(8, -1)获得type
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  };
})(Object.create(null));

/**
 * 判断一个值是否是纯对象
 *
 * @param {Object} val 要判断的值
 * @return {boolean} 如果是纯对象则返回 True , 否则 false
 */
function isPlainObject(val) {
  // 不是对象类型直接为false
  if (kindOf(val) !== 'object') {
    return false;
  }

  var prototype = Object.getPrototypeOf(val);
  // prototype为null 或等于 Object.prototype 为纯对象
  return prototype === null || prototype === Object.prototype;
}

// merge可以接收多个需要合并的对象
// 把这些对象合并后,返回一个新的对象
function merge() {
  var result = {};
  function assignValue(val, key) {
    // isPlainObject判断一个对象时否是纯对象
    if (isPlainObject(result[key]) && isPlainObject(val)) {
      // 如果result[key]跟val是纯对象,则把它们合并成一个新的对象
      // 并把新对象赋值给result[key]
      result[key] = merge(result[key], val);
    } else if (isPlainObject(val)) {
      // val是一个纯对象,合并成新的对象,并重新赋值给key
      // 生成新对象的目的是为了不产生副作用,当对新对象进行操作时,源对象不会受到影响
      result[key] = merge({}, val);
    } else if (isArray(val)) {
      // 如果val是数组,则slice出一个新的数组
      result[key] = val.slice();
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    // 1.2小节已实现 forEach 函数
    forEach(arguments[i], assignValue);
  }
  return result;
}