preface

If you create axios using the axios.create({}) method when using axios, you will find that you cannot use the all, spread, Cancel, CancelToken, and isCancel methods.

I looked it up online and axios maintainers tell you to reintroduce the Axios package to get things done. I don’t like this method because if I reintroduce it, my AXIos configuration will be lost and need to be reconfigured, which is too much trouble.

Because a lot of times in our project, we don’t want to use the default configuration, we want to use axiOS instances with custom Settings. For example, setting the base URL and timeout:

let newAxios = axios.create({
  baseURL: 'https://www.google.com.hk'.timeout: 1000
})
Copy the code

Once you’re done, use newaxios.post to complete your requirements. Of course, if you just use basic methods like GET, POST, and PUT, this is fine. But if you use the all, Spread, Cancel, CancelToken, isCancel methods, it will tell you that the method does not exist.

Now, let’s take a look at how the axios source code is implemented and why all, spread, and so on cannot be used with the axios.create method.

The body of the

We’ll start by opening the lib/axios.js file in the axios source directory. This file is the Axios entry. That’s where the create function is. Let’s take a look at the create source code:

axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
Copy the code

Let’s go through it step by step. When you look at the mergeConfig method, you can take it literally. This is a way to merge configurations. Merge our configuration with the default configuration, overwriting our configuration with the default configuration. The mergeConfig code, which I won’t go into here, is available for those interested. So now the code looks like this:

axios.create = function create(instanceConfig) {
  return createInstance({
    baseURL: 'https://www.google.com.hk'.timeout: 1000.xsrfCookieName: 'XSRF-TOKEN'.xsrfHeaderName: 'X-XSRF-TOKEN'.maxContentLength: - 1./ * and so on * /
  });
};
Copy the code

Now it’s a little bit clearer. Now we see that there is only one function left: createInstance. Now let’s see:

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

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context);

  return instance;
}
Copy the code

The context variable content is axios instance code. Let’s take a look at what the inside looks like:

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

// Provide aliases for supported request methods
utils.forEach(['delete'.'get'.'head'.'options'].function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});

utils.forEach(['post'.'put'.'patch'].function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});
Copy the code

The context variable contains the Request Delete, Get, Head, Options, POST, PUT patch method, and the Request Interceptors object.

Now, let’s look at the bind and extend methods below:

var instance = bind(Axios.prototype.request, context);

// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);

// Copy context to instance
utils.extend(instance, context);
Copy the code

The first bind function refers this in axios.prototype. request to the context variable.

The latter two extend methods copy the enumerable object of the second argument into the first argument, the instance variable.

We started with the first bind method, and now we have a request method in the instance variable.

The second extend method copies the Axios. Prototype method into the instance variable. Now the instance variable has request delete GET Head Options POST Put Patch methods.

Finally, the third extend method copies methods from the context into the instance variable. Request delete GET Head Options POST PUT Patch Interceptors defaults

And then it’s gone. The create method returns the instance variable directly. Do not see all, spread, etc methods. This is why these methods cannot be used with the create method. So where are these methods? Again in lib/axios.js:

// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');

// Expose all/spread
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = require('./helpers/spread');

module.exports = axios;

// Allow use of default import syntax in TypeScript
module.exports.default = axios;
Copy the code

As you can see, we’re assigning these methods directly to the AXIos method, and then we’re exposing them directly. So when we use Axios we can use all, spread, etc. However, with axios.create, you cannot use the all, spread, Cancel, CancelToken, isCancel methods.

The solution

If you can change the axios source code, you can change lib/axios.js to the following:

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

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context);

  utils.extend(instance, {
    Cancel: require('./cancel/Cancel'),
    CancelToken: require('./cancel/CancelToken'),
    isCancel: require('./cancel/isCancel'),
    all: function all(promises) {
      return Promise.all(promises);
    },
    spread: require('./helpers/spread')
  }, context);

  return instance;
}
Copy the code

But, of course, that’s impossible. So, we need to implement it without changing the source code.

There’s a violent solution, but I like it:

let axios = require('axios');

const http = axios.create({
  baseURL: 'https://www.google.com.hk'
})

/* eslint-disable no-proto */
http.__proto__ = axios
/* eslint-enable */

module.exports = axios
Copy the code

Isn’t it simple, one line of code to solve the problem. The reason for this comment is because reassigning __proto__ is not allowed in ESLint.