建立axios對象

axios源碼目錄結構node

建立axios對象react

axios.js是axios源碼的第一個文件,建立axios對象,基於Axios類型。ios

可是不是普通的調用構造函數,而是在Axios.prototype.request的基礎上添加了不少屬性,因此axios對象自己實際上是一個函數,一個擁有不少屬性的函數。web

圖解以下:json

下面是axios.js源代碼axios

'use strict';

var utils = require('./utils');
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var mergeConfig = require('./core/mergeConfig');
var defaults = require('./defaults');

/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  //調用Axios構造函數建立Axios新實例,傳入默認設置defaultConfig
  var instance = bind(Axios.prototype.request, context);
  //bind方法返回一個綁定了指定this的方法,此處將Axios.prototype.request的this綁定爲context
  //也就是說instance如今是一個function,而且它執行時的this是Axios傳遞了默認設置的新實例

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);
  //調用extend方法擴展instance,將Axios原型上的屬性都複製到instance上,而且Axios原型上的方法的this都綁定爲context

  // Copy context to instance
  utils.extend(instance, context);
  //調用extend方法繼續擴展instance,將Axios傳遞了默認設置的新實例的屬性都複製到instance上

  //通過上面的操做後,instance是一個function,也就是Axios.prototype.request方法,而且它上面擁有全部Axios原型上的屬性,還有傳遞了默認設置的Axios新實例的屬性

  return instance;
}

// Create the default instance to be exported
var axios = createInstance(defaults);
//調用createInstance方法建立一個新axios實例
//這個新實例其實就是Axios.prototype.request方法,它身上有Axios原型上的屬性和默認設置的Axios新實例的屬性

// Expose Axios class to allow class inheritance
axios.Axios = Axios;
//爲axios添加Axios屬性,暴露出Axios類

// Factory for creating new instances
//axios上添加create方法,用於工廠模式建立新的axios對象,能夠傳入自定義的設置,自定義設置會被Axios構造函數接收
//注意,mergeConfig方法,config1上同名屬性會覆蓋config2上的,即axios.defaults會覆蓋掉instanceConfig同名屬性
axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

// Expose Cancel & CancelToken
//暴露Cancel,CancelToken,isCancel方法
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');

// Expose all/spread
//暴露all和spread方法
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = require('./helpers/spread');

module.exports = axios;//導出axios對象

// Allow use of default import syntax in TypeScript
//容許使用typeScript中默認導入的語法
module.exports.default = axios;

defaults默認配置react-native

'use strict';

var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');

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

function setContentTypeIfUnset(headers, value) {//若是headers中沒有設置就設置新的Content-Type
  if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
    headers['Content-Type'] = value;
  }
}

function getDefaultAdapter() {//獲取默認適配器
  var adapter;
  // Only Node.JS has a process variable that is of [[Class]] process
  //只有nodejs環境下才有process對象,是Process類的實例
  if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    // For node use HTTP adapter
    adapter = require('./adapters/http');//nodejs環境的請求工具
  } else if (typeof XMLHttpRequest !== 'undefined') {
    // For browsers use XHR adapter
    adapter = require('./adapters/xhr');//瀏覽器環境的請求工具
  }
  return adapter;
}

var defaults = {
  adapter: getDefaultAdapter(),//根據環境獲取默認請求工具

  transformRequest: [function transformRequest(data, headers) {
    //默認transformRequest配置項,在請求發送以前修改data和headers
    normalizeHeaderName(headers, 'Accept');//標準化Accept header名
    normalizeHeaderName(headers, 'Content-Type');//標準化Content-Type header名
    if (utils.isFormData(data) ||
      utils.isArrayBuffer(data) ||
      utils.isBuffer(data) ||
      utils.isStream(data) ||
      utils.isFile(data) ||
      utils.isBlob(data)
      //判斷data是不是FormData對象,ArrayBuffer對象,是不是Buffer,是不是Stream,是不是文件,是不是blob
    ) {//若是是,直接返回data
      return data;
    }
    if (utils.isArrayBufferView(data)) {//若是data是ArrayBuffer的視圖,就返回data.buffer
      return data.buffer;
    }
    if (utils.isURLSearchParams(data)) {//若是data是URLSearchParams對象,設置header後返回data.toString()
      setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
      return data.toString();
    }
    if (utils.isObject(data)) {//若是data是對象,設置新的Content-Type後返回JSON.stringify(data)
      setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
      return JSON.stringify(data);
    }
    return data;//返回data
  }],

  transformResponse: [function transformResponse(data) {//默認transformResponse配置項
    /*eslint no-param-reassign:0*/
    if (typeof data === 'string') {//若是是data是字符串
      try {
        data = JSON.parse(data);//嘗試解析data
      } catch (e) { /* Ignore */ }
    }
    return data;
  }],

  /**
   * A timeout in milliseconds to abort a request. If set to 0 (default) a
   * timeout is not created.
   */
  timeout: 0,//超時時間,默認爲0,意思是不設置超時時間

  xsrfCookieName: 'XSRF-TOKEN',//存下xsrf token的cookie名字
  xsrfHeaderName: 'X-XSRF-TOKEN',//攜帶xsrf token的http header名字

  maxContentLength: -1,//定義http響應主體的最大尺寸

  validateStatus: function validateStatus(status) {
    //定義一個函數,根據響應的狀態值判斷promise是否應該resolve或者reject
    //若是validateStatus返回true,就resolve;不然,就會reject
    return status >= 200 && status < 300;
  }
};

defaults.headers = {//默認請求頭
  common: {
    'Accept': 'application/json, text/plain, */*'
  }
};

utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
  //爲以上類型請求添加默認頭部
  defaults.headers[method] = {};
});

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  //爲以上類型請求添加默認頭部
  defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});

module.exports = defaults;

utils工具函數數組

'use strict';

var bind = require('./helpers/bind');
var isBuffer = require('is-buffer');

/*global toString:true*/

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString;

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Array, otherwise false
 */
//判斷一個值是不是一個數組
function isArray(val) {
  return toString.call(val) === '[object Array]';
}

/**
 * Determine if a value is an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an ArrayBuffer, otherwise false
 */
//判斷一個值是不是一個ArrayBuffer對象
function isArrayBuffer(val) {
  return toString.call(val) === '[object ArrayBuffer]';
}

/**
 * Determine if a value is a FormData
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an FormData, otherwise false
 */
//判斷一個值是不是FormData對象
function isFormData(val) {
  return (typeof FormData !== 'undefined') && (val instanceof FormData);
}

/**
 * Determine if a value is a view on an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
 */
//判斷一個值是不是一個ArrayBuffer的視圖
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer);
  }
  return result;
}

/**
 * Determine if a value is a String
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a String, otherwise false
 */
//判斷一個值是不是字符串
function isString(val) {
  return typeof val === 'string';
}

/**
 * Determine if a value is a Number
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Number, otherwise false
 */
//判斷一個值是不是一個數字
function isNumber(val) {
  return typeof val === 'number';
}

/**
 * Determine if a value is undefined
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if the value is undefined, otherwise false
 */
//判斷一個值是不是undefined
function isUndefined(val) {
  return typeof val === 'undefined';
}

/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Object, otherwise false
 */
//判斷一個值是不是一個對象
function isObject(val) {
  return val !== null && typeof val === 'object';
}

/**
 * Determine if a value is a Date
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Date, otherwise false
 */
//判斷一個值是不是日期對象
function isDate(val) {
  return toString.call(val) === '[object Date]';
}

/**
 * Determine if a value is a File
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a File, otherwise false
 */
//判斷一個值是不是一個文件
function isFile(val) {
  return toString.call(val) === '[object File]';
}

/**
 * Determine if a value is a Blob
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Blob, otherwise false
 */
//判斷一個值是不是一個blob對象
function isBlob(val) {
  return toString.call(val) === '[object Blob]';
}

/**
 * Determine if a value is a Function
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Function, otherwise false
 */
//判斷一個值是不是一個函數
function isFunction(val) {
  return toString.call(val) === '[object Function]';
}

/**
 * Determine if a value is a Stream
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Stream, otherwise false
 */
//判斷一個值是不是Stream
function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

/**
 * Determine if a value is a URLSearchParams object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
//判斷一個值是不是一個URLSearchParams對象
function isURLSearchParams(val) {
  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}

/**
 * Trim excess whitespace off the beginning and end of a string
 *
 * @param {String} str The String to trim
 * @returns {String} The String freed of excess whitespace
 */
//去除字符串首尾的空白字符
function trim(str) {
  return str.replace(/^\s*/, '').replace(/\s*$/, '');
}

/**
 * Determine if we're running in a standard browser environment
 *
 * This allows axios to run in a web worker, and react-native.
 * Both environments support XMLHttpRequest, but not fully standard globals.
 *
 * web workers:
 *  typeof window -> undefined
 *  typeof document -> undefined
 *
 * react-native:
 *  navigator.product -> 'ReactNative'
 * nativescript
 *  navigator.product -> 'NativeScript' or 'NS'
 */
//判斷是否運行在標準瀏覽器環境中
//這使得axios能夠運行在web worker和react-native中
function isStandardBrowserEnv() {
  if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
                                           navigator.product === 'NativeScript' ||
                                           navigator.product === 'NS')) {
    return false;
  }
  return (
    typeof window !== 'undefined' &&
    typeof document !== 'undefined'
  );
}

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
//循環一個數組或者一個對象,爲每個元素或者屬性調用function
function forEach(obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {//obj爲空,直接返回
    return;
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    //若是obj不是object類型,說明不可遍歷,強制轉換成一個數組
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  if (isArray(obj)) {//若是obj是數組,遍歷數組,每一次循環調用一次fn,接收參數依次爲value,index,array
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {//若是obj不是數組是對象
    // Iterate over object keys
    for (var key in obj) {//使用for in循環
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        //只有噹噹前key是obj自身屬性的時候才調用fn,接收參數依次爲value,key,object
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

/**
 * Accepts varargs expecting each argument to be an object, then
 * immutably merges the properties of each object and returns result.
 *
 * When multiple objects contain the same key the later object in
 * the arguments list will take precedence.
 *
 * Example:
 *
 * ```js
 * var result = merge({foo: 123}, {foo: 456});
 * console.log(result.foo); // outputs 456
 * ```
 *
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
//接收可變參數要求每一個參數都是對象類型,合併每個對象的屬性而後返回結果對象
//若是多個對象包含一樣的key,參數列表裏越靠後的對象的屬性將會覆蓋以前的值
function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};//結果對象初始化
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      //若是結果對象上key對應的值是object類型而且當前key對應的value也是object類型
      //遞歸調用merge合併對象屬性
      result[key] = merge(result[key], val);
    } else {//若是key對應值是簡單值,直接賦值
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    //循環參數列表,對每個參數列表裏的object再調用forEach循環它的屬性,assignValue將它的屬性賦到結果對象上
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Function equal to merge with the difference being that no reference
 * to original objects is kept.
 *
 * @see merge
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
//深層合併,合併全部對象的屬性生成新的對象,去掉全部引用類型的引用
//即徹底建立一個新的對象,和舊的對象不會互相影響
function deepMerge(/* obj1, obj2, obj3, ... */) {
  var result = {};//結果對象
  function assignValue(val, key) {//val是屬性值,key是屬性鍵
    if (typeof result[key] === 'object' && typeof val === 'object') {
      //若是結果對象上對應key的值是object類型,而且當前屬性值val也是對象類型,遞歸調用deepMerge繼續深一層合併對象
      result[key] = deepMerge(result[key], val);
    } else if (typeof val === 'object') {
      //若是當前屬性值val是對象類型,遞歸調用deepMerge繼續深一層合併對象
      result[key] = deepMerge({}, val);
    } else {
      //若是當前屬性值是簡單值,直接賦值
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    //循環參數數組,對每一個obj調用forEach循環,對obj的屬性調用assignValue將屬性複製到結果對象上
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Extends object a by mutably adding to it the properties of object b.
 *
 * @param {Object} a The object to be extended
 * @param {Object} b The object to copy properties from
 * @param {Object} thisArg The object to bind function to
 * @return {Object} The resulting value of object a
 */
//將b對象的屬性擴展到a對象上,返回擴展後的a對象
function extend(a, b, thisArg) {
  //forEach循環b對象
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      //若是當前val是function而且傳遞了thisArg,就將val的this綁定爲thisArg,而後將此屬性複製到a對象上
      a[key] = bind(val, thisArg);
    } else {//若是不是function,直接複製到a對象上
      a[key] = val;
    }
  });
  return a;//返回擴展後的a對象
}

module.exports = {
  isArray: isArray,
  isArrayBuffer: isArrayBuffer,
  isBuffer: isBuffer,
  isFormData: isFormData,
  isArrayBufferView: isArrayBufferView,
  isString: isString,
  isNumber: isNumber,
  isObject: isObject,
  isUndefined: isUndefined,
  isDate: isDate,
  isFile: isFile,
  isBlob: isBlob,
  isFunction: isFunction,
  isStream: isStream,
  isURLSearchParams: isURLSearchParams,
  isStandardBrowserEnv: isStandardBrowserEnv,
  forEach: forEach,
  merge: merge,
  deepMerge: deepMerge,
  extend: extend,
  trim: trim
};
mergeConfig
將默認配置和自定義配置合併成一個配置的方法
'use strict';

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

/**
 * Config-specific merge-function which creates a new config-object
 * by merging two configuration objects together.
 *
 * @param {Object} config1
 * @param {Object} config2
 * @returns {Object} New object resulting from merging config2 to config1
 */
//合併兩個設置對象爲一個設置對象
//在生成最終結果對象的時候,都是先加入config2後加入config1的屬性,config1上同名屬性會覆蓋config2上的
module.exports = function mergeConfig(config1, config2) {
  // eslint-disable-next-line no-param-reassign
  config2 = config2 || {};
  var config = {};//結果對象

  utils.forEach(['url', 'method', 'params', 'data'], function valueFromConfig2(prop) {
    //調用forEach循環url,method,params,data這幾個設置對象中的設置項
    //判斷若是config2中這四個設置項不爲undefined,就將其加入config結果對象中
    if (typeof config2[prop] !== 'undefined') {
      config[prop] = config2[prop];
    }
  });

  utils.forEach(['headers', 'auth', 'proxy'], function mergeDeepProperties(prop) {
    //調用forEach循環headers,auth,proxy這幾個設置項
    if (utils.isObject(config2[prop])) {
      //若是config2中的對應設置項是對象,調用deepMerge深層合併config1和config2上的設置項而後加入到結果對象中
      config[prop] = utils.deepMerge(config1[prop], config2[prop]);
    } else if (typeof config2[prop] !== 'undefined') {
      //若是config2上對應設置項不是object是簡單類型,而且不爲undefined,就加入config結果對象中
      config[prop] = config2[prop];
    } else if (utils.isObject(config1[prop])) {
      //若是config1中的對應設置項是對象,調用deepMerge深層複製config1上的設置項加入到結果對象中
      config[prop] = utils.deepMerge(config1[prop]);
    } else if (typeof config1[prop] !== 'undefined') {
      //若是config1上對應設置項不是object是簡單類型,而且不爲undefined,就加入config結果對象中
      config[prop] = config1[prop];
    }
  });

  utils.forEach([
    'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer',
    'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
    'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength',
    'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken',
    'socketPath'
  ], function defaultToConfig2(prop) {
    //調用forEach循環處理其餘配置項
    if (typeof config2[prop] !== 'undefined') {
      //若是config2上對應配置項不爲undefined,加入config結果對象
      config[prop] = config2[prop];
    } else if (typeof config1[prop] !== 'undefined') {
      //若是config1上對應配置項不爲undefined,加入config結果對象
      config[prop] = config1[prop];
    }
  });

  return config;
};

bindpromise

綁定this的方法瀏覽器

'use strict';

module.exports = function bind(fn, thisArg) {
  return function wrap() {
    var args = new Array(arguments.length);
    //建立一個args數組,長度和wrap接收的參數參數長度同樣
    for (var i = 0; i < args.length; i++) {
      //循環,往args數組中插入接收到的參數
      args[i] = arguments[i];
    }
    return fn.apply(thisArg, args);
    //調用apply綁定fn的this爲指定thisArg,傳入參數數組
  };
};
相關文章
相關標籤/搜索