Axios is a promise based web request library that works with Node.js and browsers. It is isomorphic (that is, the same set of code can run in the browser and node.js). On the server side it uses the native Node.js HTTP module, while on the client side it uses XMLHttpRequests.

Axios is a network request library that can run both on the browser client and Node server side. Requests can be built with XMLHttpRequests while the browser is running, and network requests can be built with Node’s HTTP modules in the Node environment.

Today, we’ll take a look at the source code implementation of Axios, and when that’s done, we’ll implement a simple AXIos library.

Let’s start by looking at the project directory structure of the AXIos library. (As shown below)

Two things can be learned from the figure above:

  1. The core document of Axios islib/axiosSo if we just focus onaxiosWhen you run it, you just look at itlibFiles in this directory will do.
  2. Axios runs on only one third-party libraryfollow-redirectsThis library is used for processingHTTPTo redirect the request,axiosThe default behavior of redirects is follow redirects, so you can guess that this library is used to follow redirects. If you do not want to automatically follow redirects, you need to declare this explicitlymaxRedirects=0.

I have not found the official document of AXIos on Baidu, so here is an official document of AXIos for your reference.

lib/axios

Let’s open the lib/axios.js file. (As shown below)

Just focus on those core lines.

The number of rows describe
The first26 In the documentaxios.createCall iscreateInstanceFunction, which will create a new oneAxiosThe instance
The first34 A new default is createdaxiosThe instance
The first37 ~ 52 The defaultaxiosThe instance adds a number of properties and methods
The first57 Will be the defaultaxiosInstance export

Axios

Next, let’s look at the Axios class, the core of the Axios source code, located in lib/core/ axios.js.

function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}
Copy the code

Axios receives the configuration and stores the instanceConfig configuration in the axios.defaults property for subsequent requests.

Request interceptors and response interceptors are also managed through the InterceptorManager, which we’ll talk about later.

The default instance of AXIos will be created using the configuration in lib/defaults.js.

From the Axios setting, we can see why this part of the documentation changes the configuration. (As shown below)

We can also see that Axios instances are the smallest unit of Axios’ network request-default configuration, and that there is no set of “global default configurations” shared by all instances.

But we can do it in two ways.

One way to do this is to write two sets of configurations, a global default configuration and a personalized configuration for each instance, and manually merge them when creating an AXIos instance.

Of course, there’s a smarter way to do this, so let’s look at P1’s createInstance method.

function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  var instance = bind(Axios.prototype.request, context);
  
  / /...

  instance.create = function create(instanceConfig) {
    // defaultConfig is inherited through closures. The newly created instance inherits the configuration of the original instance
    return createInstance(mergeConfig(defaultConfig, instanceConfig));
  };

  return instance;
}
Copy the code

As you can see from the code, the createInstance method inherits the defaultConfig configuration internally through a closure, and the newly created instance inherits the configuration of the original instance.

This way, we can also create an axios instance with a set of global default configurations, and then use that AXIos instance to create other AXIos instances by calling the axios/instance.create method. This way all AXIOS instances can inherit the global default configuration.

InterceptorManager — InterceptorManager

Let’s now take a look at the InterceptorManager, an internal interception manager in Axios. (As shown below)

The overall implementation of the InterceptorManager is fairly simple, with a Handlers array that holds all interceptors registered with the Use method.

The use method returns handlers.leng-1 as the interceptor ID, and when the eject method is called, the interceptor with the corresponding id subscript is set to NULL.

The forEach method traverses all interceptor methods, executing the fn callback passed in, passing the interceptor as an argument to fn.

The InterceptorManager only collects and manages interceptors, not the execution logic of interceptors.

But I feel like the forEach method is a little redundant, so if I were doing it, I would probably just expose a getter method to fetch handlers externally. Here the author’s design may have some other considerations, I have not yet thought of.

request

Next, let’s look at the core method of the Axios class, the Request method, which Axios uses to initiate a real network request.

This is a long piece of code, and I’m going to parse it line by line. The handling of interceptors and requests in the Request method is very elegant, and I’ll focus on that.

I will directly introduce the relatively simple part in the table (as follows).

The number of rows describe
The first32 ~ 41 Determine the first parameter, assemblyconfigConfiguration, disable NoneurlThe request of
The first46 ~ 52 Sets the request method, using the default configured request method if it is not specified, or using the default request method if it is not specifiedgetrequest

Let’s focus on interceptor handling, starting with request interceptors.

There are two parameters that are not specified in the documentation, which are explained here:

  • The first58To use:useIn the third parameter when registering an interceptoroptions.runWhenMethod will be called first if the method returnsfalse, the request interceptor is skipped.
  • The first62To use:useIn the third parameter when registering an interceptoroptions.synchronousThe argument explicitly declares the interceptor to besynchronousOtherwise, the default value isasynchronousInterceptors will passpromiseCall. — Actually I think this parameter is meaningless, unificationasynchronousIt’ll be ok. Maybe the authors have some other synchronization scenarios in mind that I haven’t thought of yet.

Important note: Line 64 uses the unshift method to add the request interceptor in registered reverse order to the requestInterceptorChain for subsequent execution.

This means that when interceptors are requested to make changes to the same configuration, subsequent interceptors cannot override previous interceptors.

Take a look at the request interceptor example below.

After setting the interceptor does not appear to work, read the source code we know, in fact, the execution order caused by.

Axios is probably designed this way to prevent request interceptor abuse from overwriting the configuration by subsequent handlers. This is not documented, and it can cause some confusion if this happens to be the case.

Responder interceptors are much easier to handle and I don’t need to explain. (As shown below)

Slightly noteworthy is that the interceptor adds both success and error handling to the internal interceptor array, which looks like this inside the array:

[' interceptor successfully processed handler ', 'interceptor error handler ',' interceptor successfully processed handler ', 'interceptor error handler ',...]

Understanding this data structure will help you understand the implementation of the last core code (figure below)

We need to parse each line of code line by line:

The number of rows describe
The first74 Determines whether it is an asynchronous request interceptor (default: yes)
The first75 The statementchainArray, the first element of which is the method that initiates the requestfetchMethod), the second element is for82The line of dutyundefined
The first77 All of theRequest interceptorAdded to thechainThe leading position of
The first78 All of theResponse interceptorAdded to thechainTail position of
The first80 ~ 83 withconfigBuild the first onePromise“, and then do it in sequencechainRequest interceptor -> The real request -> Response interceptorIs passed in each executionSuccess handler function(asresolve) andFailure handler function(asreject)

The last chain execution elegantly illustrates axios’s internal workflow, which is the core set of request interceptors -> Real Request -> response interceptors.

I suggest you take a closer look at the last section of the function.

There is also a paragraph about synchronous request interceptor processing, is basically similar, interested children can read for themselves.

summary

That’s it, axios’s basic structure and core workflow.

In the next chapter, I will analyze the real request — dispatchRequest in detail. Please stay tuned.

One last thing

If you’ve already seen it, please give it a thumbs up

Your likes are the greatest encouragement to the author, and can also let more people see this article!

If you find this article helpful, please help to light up the star on Github.