In many background management systems, loading is required to be opened when a request is sent and to be closed when a response is received. For this general logic, I usually do this in the AXIos interceptor, because not every request needs to display loading globally. Therefore, I added a flag showLoading in axios config to indicate whether loading should be displayed before sending the request. After receiving the response, I would use this flag to determine whether loading should be disabled. The code in axios interceptor is as follows:


axios.interceptors.request.use(
  (config) = > {
    // If showLoading is not specified in config or is true, loading needs to be displayed globally
    if(config.headers.showLoading ! = =false) {
      // Display loading globally
      Loading.showLoading();
    }
    return config;
  },
  (err) = > {
    return Promise.reject(err); }); instance.interceptors.response.use((response) = > {
    const { config: { headers } } = response;
    if(headers.showLoading ! = =false) {
      // Disable loading globally
      Loading.hideLoading();
    }
    returndata; });Copy the code

I naturally think that the above implementation meets the requirements, but once I talked to my backend colleague about this problem. The backend colleague asked me how could the front-end mark (showLoading) be transferred to the backend server, and he told me that he would never allow me to do so if he was connecting with me. And then I got stuck, because I couldn’t think of a solution.

Until I realized that the Onion model actually requests and responds naturally to the onion model, and if I add the Onion model to Axios, this problem will be solved by itself. Here’s how to add an Onion model to Axios. If you have an Onion model, you don’t need an Axios interceptor because the Onion model is much better than the Axios interceptor.

  1. Declare the MiddleWareManager class, which is a concrete implementation of the Onion model, as shown below.
// Middleware manager for adding and removing middleware.
// In addition, this added middleware for who to use, also need to save the parameter (job).
class MiddleWareManager {
  If the middleware is for Axios, then that job is the axios method.
  // middleWares is used to store middleware.
  // Job and middleware are methods that return Promise objects.
  // Job takes a parameter, config, which is passed by the last middleware.
  // The middleware takes two parameters, the config passed by the previous middleware and the method to execute the next middleware.
  constructor(job) {
    // The axios request is added by default
    this.job = job;
    this.middleWares = [];
  }

  use(middleWare) {
    this.middleWares.unshift(middleWare);
    return this;
  }

  remove(middleWare) {
    const index = this.middleWares.indexOf(middleWare);
    this.middleWares.splice(index, 1);
    return this;
  }

  run(config) {
    const { length } = this.middleWares;
    function innerRun(config, index) {
      // If the middleware has finished executing, this is the direct job function.
      if (index >= length) {
        return this.job(config);
      }
      // Otherwise the next middleware function is executed
      return this.middleWares[index](config, (config) = > innerRun(config, index++));
    }
    innerRun(config, 0); }}Copy the code
  1. MiddleWareManager has been implemented, so here’s how to use the MiddleWareManager and AXIOS together. We’ll define a Request method, and we’ll call the Request method when we need to send a request.

// middleWare1 is used to handle whether display loading is required globally
async function middleWare1(config, next) {
  // Check whether the config file has the showLoading flag. If it does not or is true, the loading flag needs to be displayed globally.
  // When the response is received, the loading must be disabled
  // After receiving the response naturally, use this flag to determine whether to turn off loading
  const{ showLoading, ... rest } = config;if(showLoading ! = =false) {
    // Display loading animation
  }
  const response = await next(rest);
  if(showLoading ! = =false) {
    // Close the animation
  }
  return response;
}

/ / assembly MiddleWareManager
const manager = new MiddleWareManager(axios);
manager.use(middleWare1);

// Implement the request method to send a request
function request(config) {
  return manager.run(config);
}

Copy the code
  1. When we need to enable loading globally to send a request, do as follows

request({
  url: 'xxx'.method: 'get'
})

Copy the code

In this way, loading will be automatically enabled before sending a request and automatically disabled after receiving a response. When loading is not automatically enabled, we simply add showLoading: false to config when sending the request. The code is as follows


request({
  url: 'xxx'.method: 'get'.showLoading: false
})

Copy the code

Does this satisfy the requirements of the backend colleagues? The Onion model is also more convenient to use than the interceptor, especially when accessing the same variables in the request and response. For example, showLoading is our example. Of course, we can also move more functions of interceptors into the Middleware of the Onion model, such as automatically adding tokens when sending requests.