The adapter parses the source code for the adapter part. Here’s how to parse the code for the core tool methods, starting with the default.js and /cancel directories.

In github.com/MageeLin/ax… The Analysis branch in can see the currently parsed file.

default.js

In the default.js file, we end up exporting 10 variables and methods, all of which, as the name implies, serve the default function:

  • transitional: Default transitionoptionHint flag (deprecated in later versions)
  • adapter: Default adapter
  • transformRequest: The default request converter
  • transformResponse: The default response converter
  • timeout: Default timeout (0Unrestricted representation)
  • xsrfCookieName: the defaultXSRFcookieconfiguration
  • xsrfHeaderName: the defaultXSRFheaderconfiguration
  • maxContentLength: the defaultcontentMaximum length limit
  • maxBodyLength: the defaultbodyMaximum length limit
  • validateStatus: Default state validator (200-300.Is considered a normal response)
  • headers: the defaultheaderConfiguration, as shown below
defaults.headers = {
  common: {
    Accept: 'application/json, text/plain, */*',},delete: {},
  get: {},
  head: {},
  post: {
    'Content-Type': 'application/x-www-form-urlencoded',},put: {
    'Content-Type': 'application/x-www-form-urlencoded',},patch: {
    'Content-Type': 'application/x-www-form-urlencoded',}};Copy the code

The source code of default.js is as follows:

'use strict';

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

// The default content-type is form-urlencoded
var DEFAULT_CONTENT_TYPE = {
  'Content-Type': 'application/x-www-form-urlencoded'};// If content-type is not set, set content-type to value
function setContentTypeIfUnset(headers, value) {
  if (
    !utils.isUndefined(headers) &&
    utils.isUndefined(headers['Content-Type'])
  ) {
    headers['Content-Type'] = value; }}// Get the default adapter
function getDefaultAdapter() {
  var adapter;
  if (typeofXMLHttpRequest ! = ='undefined') {
    // The browser uses XHR Adapter
    adapter = require('./adapters/xhr');
  } else if (
    typeofprocess ! = ='undefined' &&
    Object.prototype.toString.call(process) === '[object process]'
  ) {
    // Nodejs uses HTTP Adapter
    adapter = require('./adapters/http');
  }
  return adapter;
}

var defaults = {
  // The following three options are transitional
  transitional: {
    silentJSONParsing: true.forcedJSONParsing: true.clarifyTimeoutError: false,},// Select the default adapter
  adapter: getDefaultAdapter(),

  // Convert when requested
  transformRequest: [
    function transformRequest(data, headers) {
      // Standardize accept and content-type headers
      normalizeHeaderName(headers, 'Accept');
      normalizeHeaderName(headers, 'Content-Type');

      // FormData, ArrayBuffer, Buffer, Stream, File, Blob, returns data directly
      if (
        utils.isFormData(data) ||
        utils.isArrayBuffer(data) ||
        utils.isBuffer(data) ||
        utils.isStream(data) ||
        utils.isFile(data) ||
        utils.isBlob(data)
      ) {
        return data;
      }
      // ArrayBuffer returns buffer when the View type is specified
      if (utils.isArrayBufferView(data)) {
        return data.buffer;
      }
      // URLSearchParam returns the result of the toString method
      if (utils.isURLSearchParams(data)) {
        setContentTypeIfUnset(
          headers,
          'application/x-www-form-urlencoded; charset=utf-8'
        );
        return data.toString();
      }
      Returns the result of stringify if it is another object or if the Content-type is json
      if (
        utils.isObject(data) ||
        (headers && headers['Content-Type'= = ='application/json')
      ) {
        setContentTypeIfUnset(headers, 'application/json');
        return JSON.stringify(data);
      }
      returndata; },].// Convert when responding
  transformResponse: [
    function transformResponse(data) {
      var transitional = this.transitional;
      var silentJSONParsing = transitional && transitional.silentJSONParsing;
      var forcedJSONParsing = transitional && transitional.forcedJSONParsing;
      varstrictJSONParsing = ! silentJSONParsing &&this.responseType === 'json';

      // Parse the response result
      if (
        strictJSONParsing ||
        (forcedJSONParsing && utils.isString(data) && data.length)
      ) {
        try {
          return JSON.parse(data);
        } catch (e) {
          // Return an error object when an error is reported
          if (strictJSONParsing) {
            if (e.name === 'SyntaxError') {
              throw enhanceError(e, this.'E_JSON_PARSE');
            }
            throwe; }}}returndata; },]./** * Timeout to abort a request in milliseconds. If set to 0 (the default), timeouts are not limited. * /
  timeout: 0.// XSRF configuration
  xsrfCookieName: 'XSRF-TOKEN'.xsrfHeaderName: 'X-XSRF-TOKEN'.// Maximum length limits for content and body
  maxContentLength: -1.maxBodyLength: -1.// Check the status. Only requests starting with 2 are normal responses
  validateStatus: function validateStatus(status) {
    return status >= 200 && status < 300; }};/ / the default headers
defaults.headers = {
  common: {
    Accept: 'application/json, text/plain, */*',}};// Set the content-type of the six methods
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;
Copy the code

/ cancel

The contents of the/Cancel directory are related to actively canceling the Axios request and contain three files.

├─ Cancel // Cancel request │ canceltoken.js │ isCanceltoken.jsCopy the code

Axios’ Cancel Token API is packaged based on TC39’s Cancelable Promises Proposal. You need to manually add the cancelToken attribute to the configuration item to implement the “cancel” function by executing the parameter of the callback function.

Source code analysis

This piece of source code looks very unintuitive, starting with the two least dependent files:

Cancel.js

First, cancer.js implements a Cancel class, which has an instance property message, a prototype method toString to assemble and return message, and a prototype property Cancel to determine whether it is an instance of the Cancel class.

// Cancel.js
'use strict';

/** * An object of class Cancel is thrown when the operation is cancelled@class
 * @param {String} Message Cancelled message */
function Cancel(message) {
  this.message = message;
}

// Add a toString prototype method to Cancel
Cancel.prototype.toString = function toString() {
  return 'Cancel' + (this.message ? ':' + this.message : ' ');
};

// Whether it is the flag of the Cancel class
Cancel.prototype.__CANCEL__ = true;

module.exports = Cancel;
Copy the code

isCancel.js

In isCancer.js, the implementation is even simpler, returning an isCancel method that uses the flag CANCEL to determine whether it is an instance of CANCEL.

'use strict';

/ * * *@description: Determines whether it is an object of class Cancel *@param {Any} Value Indicates the value *@return {Boolean}* /
module.exports = function isCancel(value) {
  return!!!!! (value && value.__CANCEL__); };Copy the code

CancelToken.js

Canceltoken.js canceltoken.js canceltoken.js canceltoken.js canceltoken.js

// Official example 1
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // The executor function takes a cancel function as an argumentcancel = c; })});// Cancel the request
cancel();
Copy the code

CancelToken: CancelToken: CancelToken: CancelToken: CancelToken:

// CancelToken.js
/** * 'CancelToken' is the class ** used to cancel the requested operation@class
 * @param {Function} Executor executor */
function CancelToken(executor) {
  // Determine the type of the actuator
  if (typeofexecutor ! = ='function') {
    throw new TypeError('executor must be a function.');
  }

  // Define a Promise and use scope to get resolve
  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  // Pass the operator the argument "cancel function", which is passed to the caller via the closure
  // The end goal is to take the resolvePromise outside of the closure twice and give it to the user to cancel
  executor(function cancel(message) {
    if (token.reason) {
      // If the reason attribute already has a value, it has been cancelled
      return;
    }

    // Resolve the Cancel object
    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}
Copy the code

Decomposing into code streams:

As you can iterate over the above source code, the most difficult part of this is that “resolve” is finally brought externally through two layers of closures.

The remaining two prototype methods are easy to understand. One is throwIfRequested, which is used to throw an error object:

// CancelToken.js
/** * Throw an error Cancel object */
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason; }};Copy the code

The other is source, which is actually a factory method that implements the same principles as the official example 1 given above:

// CancelToken.js
/** * returns an object containing the new "CancelToken" object and a function that cancels "CancelToken" when called. * /
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel,
  };
};
Copy the code

Of course, Axios official also gives the use of source, as follows:

// Official example 2
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios
  .get('/user/12345', {
    cancelToken: source.token,
  })
  .catch(function (thrown) {
    if (axios.isCancel(thrown)) {
      console.log('Request canceled', thrown.message);
    } else {
      // Processing error}}); axios.post('/user/12345',
  {
    name: 'new name'}, {cancelToken: source.token,
  }
);

// Cancel the request (the message argument is optional)
source.cancel('Operation canceled by the user.');
Copy the code

conclusion

This article first introduces the 10 default properties in default.js and then takes a closer look at CancelToken, which is more difficult to understand.

Core tool method (2) to parse the other part of Axios more coupled tool method.