Through the source code learning to improve their coding ability and understand the design pattern inside the source code, and finally through their own understanding, and then imitate a simple functional version of the wheel out. I want to use this source code series to supervise my learning of source code.

1. Address and version of axios warehouse

This analysis of the AXIOS source warehouse address, version is 0.20.0, because look at the source code process will add their own comments in the source code, so deliberately saved to their own warehouse, all analysis records are in this warehouse, readers can download the need, address: AXIOS source analysis address

2. Axios source directory

Clone the AXIos source address locally, and then analyze the directory. Source code learning requires debugging for breakpoints, so it is important to know how the project code works. Here, in the AXIos directory, there is a source contribution notes md file, CONTRIBUTING. Md, so open it directly to see how the project works.

3. Run and debug axios

Run the command directly here, see the following text to explain.

// 1. Clone the official repository (you may need your own ladder) gitclonehttps://github.com/axios/axios.git // 2. Npm-g grunt // 3. Grunt Watch :build // 4. To start the debugging page, go to http://localhost:3000 NPM startCopy the code

Listen for files in the lib directory

The CONTRIBUTING. Md file knows that the project is built using grunt + webapck, and running the Axios project code requires a global installation of grunt (npm-g grunt). With the grunt watch:build command, listen for changes in files in the lib folder in real time, then trigger packaging, and finally generate the contents of the dist directory (axios.js, axios.min.js).

Interface debugging

You can package the contents of the dist directory with the command to listen for changes in the file in real time, but there is no reference to the static page of the JS file in this directory, so you need a static page for debugging. The NPM start command can start port 3000 and return a static page (the specific page code is in the Sanbox directory client.html). This static page brings in the JS file with grunt Watch :build package. We can then use this page to debug the Axios source code.

In addition to NPM start, you can use the NPM run examples command to debug the examples provided by your project. If you need to change line 80 of the emamples/server.js file for debugging, you need to change the following:

// Process axios itself
if (/axios\.min\.js$/.test(url)) {
  pipeFileToResponse(res, '.. /dist/axios.js'.'text/javascript'); // Replace the original axios.min.js file with axios.js. In this case, when the page visits axios.min.js, it returns the contents of the axios.js file
  return;
}
Copy the code

After executing the above command, you can debug the axios source code by visiting the http://localhost:3000 page and listening to the lib directory in real time.

4. Axios source initialization

4.1. Main source project structure

In the project, we use grunt+webpack. Grunt is mainly responsible for listening to the changes of files and then interpreting the dependencies. The packaging is done by WebPack, so we need to look at the webpack.config.js file.

{...entry: 'index.js'.// The project entry file
}
Copy the code

The webpack configuration file lets you know that the entry point of the project is index.js. The index.js file is very concise and there is only one import, which is the lib/axios.js file.

4.2. Initialize lib/axios.js

When initializing code, there are many code references, so let’s focus on just a few of them:

  1. The utility classes introduced by the projectExtend, forEach.AxiosConstructor,bindThe function,mergeConfigFunctions;
  2. Method to generate the instancecreateInstance;
  3. axiosThe body of thecancelRelated methods;

The project code is then tracked in the order in which the code was initialized, and the variable data associated with the change can be observed by the reader for breakpoint debugging.

4.3. Step 1: Introduce encapsulated functions

The introduction of methods such as tool classes in the initialization phase.

// File location: lib/axios.js

// Strict mode
'use strict';

/ / tools
var utils = require('./utils');
// Introduce the bind method
var bind = require('./helpers/bind');
// The Axios constructor
var Axios = require('./core/Axios');
// mergeConfig(config1, config2); Merge config2 properties onto Config1 to return a new object
var mergeConfig = require('./core/mergeConfig');
// Default configuration
var defaults = require('./defaults');
Copy the code

4.3.1. The bind method

To bind, pass in two arguments. Fn is the function to which this is bound, and thisArg is the object to which this refers.

'use strict';

// bind: bind this inside fn to thisArg and return a wrap function
module.exports = 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);
  };
};

Copy the code

Arguments is used as an array to call apply. Arguments is used as an array to call apply. Arguments is used as an array to call apply.

Example of calling bind:

// Introduce the bind method
var bind = require('./helpers/bind');

// Here is an example of how to call the bind method
var obj = {one: 1};
function fn(two) {
  console.log(this.one + two);
}

// Bind this from fn to obj and return a wrap function
var bindFn = bind(fn, obj); 
bindFn(2); // Result: 3
Copy the code

4.3.2. ForEach method

// obj: object or array to traverse
// fn: passes each of the iterated elements as arguments to the fn call
function forEach(obj, fn) {
  // If the object traversed is empty, the method is jumped
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // If the type is not an object element, add it to a new array
  if (typeofobj ! = ='object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }
	
  // isArray specifies whether obj is an array
  if (isArray(obj)) {
    // Iterate through each element in the array, calling fn and passing in the traversed element
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj); }}else {
    // Object traversal (for in traverses other properties on the prototype chain)
    for (var key in obj) {
      // Ignore the current inherited attribute
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        // Pass the value of each of the traversed properties as an argument to fn
        fn.call(null, obj[key], key, obj); }}}}Copy the code

4.3.3. Extend method

function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else{ a[key] = val; }});return a;
}
Copy the code

Iterating over each attribute or element in object or array B, adding them to object A. If each element in b is a function, bind this to this arg.

Example of calling the utils.extend method:

var axios = {};
var request = {
  "get": function () {
    console.log(this.config);
  },
  "post": function () {
    console.log(this.config); }};var obj = {
  config: 'the config attribute'
};

/* * Result: axios = {* "get": function() {* console.log(this.config); * }, * "post": function () { * console.log(this.config); *} *} * Where this is bound to the obj object **/
utils.extend(axios, request, obj);
Copy the code

4.4. Step 2: Instantiate

4.4.1. Order of invocation

  • createInstanceMethods;(lib/axios. Js)
  • AxiosConstructor and twoutils.forEachMethods;(lib/core/Axios. Js)
  • InterceptorManagerConstructor;(lib/core/Axios. Js)
  • The last of thebindandextendMethod binding;(lib/axios. Js)

Var axios = createInstance(defaults); , so we’ll focus on the createInstance function in this step.

/** * Create an Axios instance *@param {*} Default configuration * on the defaultConfig instance@returns * / Axios instance
function createInstance(defaultConfig) {
  // Return Axios instance {defaults, interceptors}
  var context = newAxios(defaultConfig); .return instance;
}
Copy the code

4.4.2. Call Axios constructor

var context = new Axios(defaultConfig); The new operator calls the Axios constructor, returns {defaults, interceptors}, and binds the request method to the context, as well as the GET, POST, DELETE, patch, and put methods. These methods are essentially calling the request method. Since none of these methods were called during initialization, the request method will be moved to the next chapter.

The Axios constructor:

/** * The Axios class binds objects to the defaults property * interceptor instances (request, response) are bound to the Interceptors property **@param {*} Configuration */ on the instanceConfig instance
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  / / the interceptor
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}
Copy the code

The Axios constructor binds to the defaults configuration when initialized, and extends the requst and Response properties in the interceptors.

4.4.3. Interceptor Constructor: InterceptorManager

There are three methods inside this constructor: use (add), eject (empty by ID), and forEach (iterate).

'use strict';

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

function InterceptorManager() {
  this.handlers = [];
}

// Add an element (success callback, failure callback) to the end of the handles array and return the index value
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1;
};

// Empty the handles array by id (index)
InterceptorManager.prototype.eject = function eject(id) {
  if (this.handlers[id]) {
    this.handlers[id] = null; }};// Iterate over the handles array and pass them to fn for execution, filtering out null elements here.
InterceptorManager.prototype.forEach = function forEach(fn) {
  utils.forEach(this.handlers, function forEachHandler(h) {
    if(h ! = =null) { fn(h); }}); };module.exports = InterceptorManager;

Copy the code

4.4.4. bind and extend

Let’s go back to where the createInstance function was initialized. The new operator calls the context object returned by the Axios constructor, At this point it has various request methods (get, POST, PUT, delete), interceptors and defaults, but the createInstance function is not finished yet

/** * Create an Axios instance *@param {*} Default configuration * on the defaultConfig instance@returns * / Axios instance
function createInstance(defaultConfig) {
  // Return Axios instance {defaults, interceptors}
  var context = new Axios(defaultConfig);
  
  // Bind the request method to the instance object context ({defaults, interceptors})
  var instance = bind(Axios.prototype.request, context);

  // Instance is the request function on the prototype chain (this is bound to contenxt)
  // The extend function adds all the request methods on the prototype chain to the instance function (js function is also an object, that is, add other properties to the function), and bind this to the instance object context
  // Object: enable instance to be executed as well as call property methods (get, POST, PUT, delete...)
  utils.extend(instance, Axios.prototype, context);

  // Extend the defaults,interceptors properties from the instance function
  utils.extend(instance, context);

  Return the instance function
  / / the instance of the function body binding now get, post, put, delete, request... And the defaults, interceptors properties
  return instance;
}
Copy the code

The instance returned by createInstance is the request function. However, instance has other property methods (get, POST, PUT, delete), as well as property defaults and interceptors on the instance. So when a project introduces the Axios library, it can either call axios(), axios.get(), and axios.post() to send a request, get the default properties via Axios.defaults, or call the interceptors via axios.Interceptors.

5. To summarize

This chapter explains in detail the source code of axios library to run and modalize, as well as the functions called when axios is initialized. Axios is essentially a function, which can be called as a function or used as an object. However, the specific logic of request and cancel method are not analyzed here, and this part will be completed later.

If you see something wrong or could be improved, feel free to comment. If you think it’s good or helpful, please like, comment, retweet and share. Thank you