Изучите общую архитектуру исходного кода axios и создайте собственную библиотеку запросов.

исходный код JavaScript

1. Введение

Здравствуйте, яВакагава. Это学习源码整体架构系列Шестой Слово «общая архитектура» кажется немного большим, скажем так, это общая структура исходного кода. В этой статье изучается код фактического склада.

学习源码整体架构系列Статья выглядит следующим образом:

1.Изучите общую архитектуру исходного кода jQuery и создайте собственную библиотеку js.
2.Изучите общую архитектуру исходного кода подчеркивания и создайте собственную библиотеку классов функционального программирования.
3.Изучите общую архитектуру исходного кода lodash и создайте собственную библиотеку классов функционального программирования.
4.Изучите общую архитектуру исходного кода sentry и создайте собственный SDK для мониторинга исключений переднего плана.
5.Изучите общую архитектуру исходного кода vuex и создайте собственную библиотеку управления состоянием.
6.Изучите общую архитектуру исходного кода axios и создайте собственную библиотеку запросов.
7.Изучите общую архитектуру исходного кода koa, проанализируйте принцип луковой модели koa и принцип совместной работы.
8.Изучите общую архитектуру исходного кода Redux и глубоко поймите принципы Redux и его промежуточного программного обеспечения.

Заинтересованные читатели могут нажать, чтобы прочитать. Следующий может бытьvue-routerисходный код.

Эта статья относительно длинная, чтобы читать ее на мобильном телефоне, вы можете прямо посмотреть на несколько картинок в статье. Рекомендуется поставить лайк или добавить в закладки и прочитать на компьютере, может быть проще будет усвоить и переварить самостоятельно, отлаживая по способу отладки в статье.

Управляемое чтение
Подробности статьиaxiosМетод отладки. подробныйaxiosРеализация таких функций, как конструкторы, перехватчики, отмены и т. д. Наконец, сравниваются другие библиотеки запросов.

Версия, изучаемая в этой статье,v0.19.0. Клон официального репозиторияmasterветвь. На данный момент (14 декабря 2019 г.), последнийcommitда2019-12-09 15:52 ZhaoXC dc4bc49673943e352,fix: fix ignore set withCredentials false (#2582).

Этот репозиторий статей находится здесьGitHub-репозиторий аксиального анализа Вакагавы. спроситьstarАх.

Если вы ищете работу, проект написан и используетсяaxios, интервьюер может спросить вас:

1. ПочемуaxiosЕго можно использовать как в качестве вызова функции, так и в качестве объекта, напримерaxios({}),axios.get.
2. Краткое описаниеaxiosпроцесс вызова.
3. Вы когда-нибудь использовали перехватчик? Каков принцип?
4. Используйтеaxiosфункция отмены? Как это достигается?
5. Почему он поддерживает отправку запросов в браузерах?nodeпослать запрос?

Такие вопросы.

2. Метод исходного кода axios для отладки Chrome и vscode

Не так давно автор ответил на вопрос по ЖихуЧто, если фронтенд в течение года не сможет понять исходный код фронтенд-фреймворка?Некоторые материалы рекомендованы, да и объем чтения неплохой, если интересно, можете глянуть. Есть четыре основных момента:

1. С помощью отладки
2. Найдите релевантные статьи с высокой репутацией
3. Запишите то, что вы не понимаете, и сверьтесь с соответствующими документами.
4. Резюме

Глядя на исходный код, отладка очень важна, поэтому автор подробно описал ее.axiosМетод отладки исходного кода, чтобы помочь некоторым читателям, которые могут не знать, как отлаживать.

2.1 Chrome для отладки среды браузера axios

Метод отладки

axiosПосле упаковкиsourcemapдокумент.

# 可以克隆笔者的这个仓库代码
git clone https://github.com/lxchuan12/axios-analysis.git
cd axios-analaysis/axios
npm install
npm start
# open [http://localhost:3000](http://localhost:3000)
# chrome F12 source 控制面板  webpack//   .  lib 目录下,根据情况自行断点调试

Эта статья через приведенный выше примерaxios/sandbox/client.htmlдля отладки.

Кстати, краткое упоминание об отладкеexampleНапример, хотя эта часть была написана в начале статьи, но потом она была удалена, и, наконец, я подумал и записал.

Найти файлaxios/examples/server.js, измените код следующим образом:

server = http.createServer(function (req, res) {
  var url = req.url;
  // 调试 examples
  console.log(url);
  // Process axios itself
  if (/axios\.min\.js$/.test(url)) {
    // 原来的代码 是 axios.min.js
    // pipeFileToResponse(res, '../dist/axios.min.js', 'text/javascript');
    pipeFileToResponse(res, '../dist/axios.js', 'text/javascript');
    return;
  }
  // 原来的代码 是 axios.min.map
  // if (/axios\.min.map$/.test(url)) {
  if (/axios\.map$/.test(url)) {
    // 原来的代码 是 axios.min.map
    // pipeFileToResponse(res, '../dist/axios.min.map', 'text/javascript');
    pipeFileToResponse(res, '../dist/axios.map', 'text/javascript');
    return;
  }
}
# 上述安装好依赖后
# npm run examples 不能同时开启,默认都是3000端口
# 可以指定端口 5000
# npm run examples ===  node ./examples/server.js
node ./examples/server.js -p 5000

Открытьhttp://localhost:5000, и тогда вы можете быть счастливы вChromeОтладка в браузереexamplesпример в.

axiosда поддержкаnodeСреда отправила запрос. Далее посмотрим, как использоватьvscodeотладкаnodeокружающая обстановкаaxios.

2.2 Отладочные аксиомы vscode в среде узла

в корневом каталогеaxios-analysis/Создайте.vscode/launch.jsonФайлы следующие:

{
    // 使用 IntelliSense 了解相关属性。
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceFolder}/axios/sandbox/client.js",
            "skipFiles": [
                "<node_internals>/**"
            ]
        },
    ]
}

согласно сF5Просто начните отладку и шаг за шагом в соответствии с вашей ситуацией.(F10), одношаговая отладка(F11)Отладка точки останова.

На самом деле проекты с открытым исходным кодом обычно имеют правила участия.axios/CONTRIBUTING.md, автор только что изменил основу этого руководства, чтобы ссылатьсяsourcemapфайл отлаживаемый.

3. Сначала посмотрите на структуру аксиом

git clone https://github.com/lxchuan12/axios-analysis.git
cd axios-analaysis/axios
npm install
npm start

В соответствии с упомянутым выше методом отладки,npm start, прямо вchromeОтладка в браузере. Открытьhttp://localhost:3000, который выводится на консольaxios, считается, что многие люди не распечатали его.

console.log({axios: axios});

Кликайте по нему слой за слоем,axiosЧто такое структура, сначала есть общее впечатление.

Автор нарисовал более подробную схему.

axios 结构关系图

После прочтения структурной схемы, если вы виделиjQuery,underscoreа такжеlodashисходный код, вы обнаружите, что он на самом деле такой же, какaxiosДизайн исходного кода аналогичен.

jQueryпсевдоним$,underscore loadshпсевдоним_Это и функция, и объект. НапримерjQueryКак использовать.$('#id'), $.ajax.

Далее посмотрите на реализацию конкретного исходного кода. Вы можете следовать точке останова для отладки.

Советы по отладке точки останова:
Оператор присваивания можно пропустить за один шаг, просто посмотрите на возвращаемое значение, а позже подробно изучите его.
Выполнение функции требует точек останова, и вы также можете использовать комментарии и контекст, чтобы отодвигать то, что делает функция.

4. Инициализация исходного кода axios

Посмотрите на исходный код Первый шаг, посмотрите сначалаpackage.json. обычно заявляютmainосновной входной файл.

// package.json
{
  "name": "axios",
  "version": "0.19.0",
  "description": "Promise based HTTP client for the browser and node.js",
  "main": "index.js",
  // ...
}

основной входной файл

// index.js
module.exports = require('./lib/axios');

4.1 lib/axios.jsосновной файл

axios.jsКод файла относительно больше. Разверните повествование, разделив его на три части.

  1. Часть 1. Знакомство с некоторыми служебными функциямиutils,AxiosКонструктор, конфигурация по умолчаниюdefaultsЖдать.
  2. Вторая часть: генерировать экземпляры объектовaxios,axios.Axios,axios.createЖдать.
  3. Третья часть отменяет соответствующую реализацию API иall,spread, экспорт и т.д.

4.1.1 Часть 1

Ввести некоторые полезные функцииutils,AxiosКонструктор, конфигурация по умолчаниюdefaultsЖдать.

// 第一部分:
// lib/axios
// 严格模式
'use strict';
// 引入 utils 对象,有很多工具方法。
var utils = require('./utils');
// 引入 bind 方法
var bind = require('./helpers/bind');
// 核心构造函数 Axios
var Axios = require('./core/Axios');
// 合并配置方法
var mergeConfig = require('./core/mergeConfig');
// 引入默认配置
var defaults = require('./defaults');

4.1.2 Часть II

заключается в создании экземпляра объектаaxios,axios.Axios,axios.createЖдать.

/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
function createInstance(defaultConfig) {
  // new 一个 Axios 生成实例对象
  var context = new Axios(defaultConfig);
  // bind 返回一个新的 wrap 函数,
  // 也就是为什么调用 axios 是调用 Axios.prototype.request 函数的原因
  var instance = bind(Axios.prototype.request, context);
  // Copy axios.prototype to instance
  // 复制 Axios.prototype 到实例上。
  // 也就是为什么 有 axios.get 等别名方法,
  // 且调用的是 Axios.prototype.get 等别名方法。
  utils.extend(instance, Axios.prototype, context);
  // Copy context to instance
  // 复制 context 到 intance 实例
  // 也就是为什么默认配置 axios.defaults 和拦截器  axios.interceptors 可以使用的原因
  // 其实是new Axios().defaults 和 new Axios().interceptors
  utils.extend(instance, context);
  // 最后返回实例对象,以上代码,在上文的图中都有体现。这时可以仔细看下上图。
  return instance;
}

// Create the default instance to be exported
// 导出 创建默认实例
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
// 暴露 Axios class 允许 class 继承 也就是可以 new axios.Axios()
// 但  axios 文档中 并没有提到这个,我们平时也用得少。
axios.Axios = Axios;

// Factory for creating new instances
// 工厂模式 创建新的实例 用户可以自定义一些参数
axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

Вот краткое описание заводской выкройки.axios.createТо есть пользователю не нужно знать, как он реализован внутри.
Например, когда мы покупаем мобильный телефон, нам не нужно знать, как он сделан, это заводской режим.
После прочтения второй части, есть несколько задействованных функций инструмента, таких какbind,extend. Эти инструменты описаны далее.

4.1.3 Привязка метода инструмента

axios/lib/helpers/bind.js

'use strict';
// 返回一个新的函数 wrap
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];
    }
    // 把 argument 对象放在数组 args 里
    return fn.apply(thisArg, args);
  };
};

Передача двух аргументов в функцию иthisArgнаправление.
Поставить параметрыargumentsСгенерируйте массив и, наконец, вызовите структуру возвращаемых параметров.
На самом деле сейчасapplyслужба поддержкиargumentsТакой подобный массиву объект не нуждается в ручном преобразовании массива.
Так зачем же автор перевернул массив, для производительности? Не поддерживается на данный момент? Или автор не в курсе? Это неизвестно. Знающие читатели могут сообщить об этом автору в комментариях.

оapply,callа такжеbindДля читателей, которые не очень знакомы, вы можете прочитать другие статьи автора.面试官问系列.
Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?

Например

function fn(){
  console.log.apply(console, arguments);
}
fn(1,2,3,4,5,6, '若川');
// 1 2 3 4 5 6 '若川'

4.1.4 utils.extend метода инструмента

axios/lib/utils.js

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;
}

Фактически, это обход параметровbобъект, скопированный вaНа объекте, если это функция, используйтеbindпередача.

4.1.5 utils.forEach метода инструмента

axios/lib/utils.js

Обход массивов и объектов. Шаблон проектирования называется шаблоном итератора. Многие исходные коды имеют подобные функции обхода. например, известныйjQuery $.each.

/**
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
function forEach(obj, fn) {
  // Don't bother if no value provided
  // 判断 null 和 undefined 直接返回
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // Force an array if not already something iterable
  // 如果不是对象,放在数组里。
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  // 是数组 则用for 循环,调用 fn 函数。参数类似 Array.prototype.forEach 的前三个参数。
  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    // Iterate over object keys
    // 用 for in 遍历对象,但 for in 会遍历原型链上可遍历的属性。
    // 所以用 hasOwnProperty 来过滤自身属性了。
    // 其实也可以用Object.keys来遍历,它不遍历原型链上可遍历的属性。
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

если правильноObjectСвязанныйAPIЕсли вы не знакомы с этим, вы можете проверить статью, которую я написал ранее.Весь API-анализ объектов JavaScript

4.1.6 Часть III

Отмените соответствующие реализации API иall,spread, экспорт и т.д.

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

// Expose all/spread
// 导出 all 和 spread API
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
// 也就是可以以下方式引入
// import axios from 'axios';
module.exports.default = axios;

Здесьspread,отменитьAPIЯ пока не буду его анализировать, а подробно разберу позже.

Допустим, у вас есть такая потребность.

function f(x, y, z) {}
var args = [1, 2, 3];
f.apply(null, args);

тогда вы можете использоватьspreadметод. Применение:

axios.spread(function(x, y, z) {})([1, 2, 3]);

Реализация также относительно проста. Реализация исходного кода:

/**
 * @param {Function} callback
 * @returns {Function}
 */
module.exports = function spread(callback) {
  return function wrap(arr) {
    return callback.apply(null, arr);
  };
};

надvar context = new Axios(defaultConfig);, за которым следует основной конструкторAxios.

4.2 Базовый конструктор Axios

axios/lib/core/Axios.js

КонструкторAxios.

function Axios(instanceConfig) {
  // 默认参数
  this.defaults = instanceConfig;
  // 拦截器 请求和响应拦截器
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}
Axios.prototype.request = function(config){
  // 省略,这个是核心方法,后文结合例子详细描述
  // code ...
  var promise = Promise.resolve(config);
  // code ...
  return promise;
}
// 这是获取 Uri 的函数,这里省略
Axios.prototype.getUri = function(){}
// 提供一些请求方法的别名
// Provide aliases for supported request methods
// 遍历执行
// 也就是为啥我们可以 axios.get 等别名的方式调用,而且调用的是 Axios.prototype.request 方法
// 这个也在上面的 axios 结构图上有所体现。
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
    }));
  };
});

module.exports = Axios;

Затем посмотрите на раздел перехватчика.

4.3 Конструктор управления перехватчиками InterceptorManager

Перехват до запроса и перехват после запроса.
существуетAxios.prototype.requestИспользуемая в функции функция, как добиться перехвата, будет подробно описано далее с примерами.

репозиторий axios github документация перехватчика

как использовать:

// Add a request interceptor
// 添加请求前拦截器
axios.interceptors.request.use(function (config) {
  // Do something before request is sent
  return config;
}, function (error) {
  // Do something with request error
  return Promise.reject(error);
});

// Add a response interceptor
// 添加请求后拦截器
axios.interceptors.response.use(function (response) {
  // Any status code that lie within the range of 2xx cause this function to trigger
  // Do something with response data
  return response;
}, function (error) {
  // Any status codes that falls outside the range of 2xx cause this function to trigger
  // Do something with response error
  return Promise.reject(error);
});

Если вы хотите поставить перехватчик, вы можете использоватьejectметод.

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

Экземпляр перехватчика может быть добавлен к пользователю.

const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

Реализация исходного кода:

Конструктор,handlesИспользуется для хранения функций перехватчика.

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

Далее объявляются три метода: use, remove, traverse.

4.3.1 Использование InterceptorManager.prototype.use

Передайте две функции в качестве параметров, один элемент в массиве хранит{fulfilled: function(){}, rejected: function(){}}. номер возвратаIDДля снятия интерцепторов.

/**
 * @param {Function} fulfilled The function to handle `then` for a `Promise`
 * @param {Function} rejected The function to handle `reject` for a `Promise`
 *
 * @return {Number} 返回ID 是为了用 eject 移除
 */
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1;
};

4.3.2 InterceptorManager.prototype.eject удален

согласно сuseвернутьIDУдалите блокировщик.

/**
 * @param {Number} id The ID that was returned by `use`
 */
InterceptorManager.prototype.eject = function eject(id) {
  if (this.handlers[id]) {
    this.handlers[id] = null;
  }
};

Что-то вроде таймераsetTimeoutа такжеsetInterval, возвращаемое значение равноid. использоватьclearTimeoutа такжеclearIntervalчтобы очистить таймер.

// 提一下 定时器回调函数是可以传参的,返回值 timer 是数字
var timer = setInterval((name) => {
  console.log(name);
}, 1000, '若川');
console.log(timer); // 数字 ID
// 在控制台等会再输入执行这句,定时器就被清除了
clearInterval(timer);

4.3.3 InterceptorManager.prototype.forEach Traversal

Перебрать все перехватчики, передать функцию обратного вызова (каждая функция перехватчика в качестве параметра) для вызова, удаленный элементnull, поэтому он не будет выполнен, а эффект удаления будет достигнут.

/**
 * @param {Function} fn The function to call for each interceptor
 */
InterceptorManager.prototype.forEach = function forEach(fn) {
  utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
      fn(h);
    }
  });
};

5. Комбинация экземпляров

Запустите во время отладки, как описано вышеnpm startиспользуетсяaxios/sandbox/client.htmlФайл пути используется в качестве примера, и читатели могут самостоятельно его отладить.

Ниже приведен фрагмент кода из этого файла.

axios(options)
.then(function (res) {
  response.innerHTML = JSON.stringify(res.data, null, 2);
})
.catch(function (res) {
  response.innerHTML = JSON.stringify(res.data, null, 2);
});

5.1 Первый взгляд на процесс стека вызовов

Если вы не хотите отлаживать шаг за шагом, есть хитрый способ.
знаниеaxiosиспользовалXMLHttpRequest.
Вы можете искать в проекте:new XMLHttpRequest.
Перейти к файлуaxios/lib/adapters/xhr.js
в этом заявленииvar request = new XMLHttpRequest();
chromeНажмите точку останова в браузере для отладки, а затем внимательно изучите реализацию определенных функций и других функций в соответствии со стеком вызовов.

Call Stack

dispatchXhrRequest (xhr.js:19)
xhrAdapter (xhr.js:12)
dispatchRequest (dispatchRequest.js:60)
Promise.then (async)
request (Axios.js:54)
wrap (bind.js:10)
submit.onclick ((index):138)

Кратко опишу процесс:

  1. Send Requestщелчок кнопкиsubmit.onclick
  2. передачаaxiosфункция на самом деле вызываетAxios.prototype.requestфункция, и эта функция используетbindвозвращает именованныйwrapФункция.
  3. передачаAxios.prototype.request
  4. (Перехватчик запроса выполняется, когда есть перехватчик запроса), и он будет выполняться в серединеdispatchRequestметод
  5. dispatchRequestзвонить послеadapter (xhrAdapter)
  6. последний звонокPromiseфункционировать вdispatchXhrRequest, (если есть перехватчик ответа, то перехватчик ответа будет вызван в конце)

Если вы внимательно прочитали статью,axios 结构关系图, по сути, имеют общее представление об этом процессе.

см. далееAxios.prototype.requestРеализация.

5.2 Основной метод запроса Axios.prototype.request

Эта функция является основной функцией. Делайте в основном следующие вещи:

1. Судя по тому, что первый параметр — это строка, задаем url, т. е. поддержкуaxios('example/url', [, config]), также поддерживаетaxios({}).
2. Объедините параметры по умолчанию и параметры, переданные пользователем
3. Установите метод запроса, по умолчанию даgetметод
4. Установите перехватчики запроса и ответа, установленные пользователем, и отправьте запросdispatchRequestсочинениеPromiseцепь, окончательный возврат по-прежнемуPromiseпример.

也就是保证了请求前拦截器先执行,然后发送请求,再响应拦截器执行这样的顺序。<br>
也就是为啥最后还是可以`then`,`catch`方法的缘故。<br>
Axios.prototype.request = function request(config) {
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  // 这一段代码 其实就是 使 axios('example/url', [, config])
  // config 参数可以省略
  if (typeof config === 'string') {
    config = arguments[1] || {};
    config.url = arguments[0];
  } else {
    config = config || {};
  }

  // 合并默认参数和用户传递的参数
  config = mergeConfig(this.defaults, config);

  // Set config.method
  // 设置 请求方法,默认 get 。
  if (config.method) {
    config.method = config.method.toLowerCase();
  } else if (this.defaults.method) {
    config.method = this.defaults.method.toLowerCase();
  } else {
    config.method = 'get';
  }
  // Hook up interceptors middleware
  // 组成`Promise`链 这段拆开到后文再讲述
};

5.2.1 СоставPromiseцепь, возвратPromiseПример

Эта часть: перехватчики запроса и ответа, установленные пользователем, тот, который отправляет запросdispatchRequestсочинениеPromiseцепь. Другими словами, он гарантирует, что перехватчик выполняется сначала перед запросом, затем отправляется запрос, а затем выполняется перехватчик ответа в этом порядке.

也就是保证了请求前拦截器先执行,然后发送请求,再响应拦截器执行这样的顺序<br>
也就是为啥最后还是可以`then`,`catch`方法的缘故。<br>

Если читательPromiseЕсли вы не знакомы с ним, рекомендуется прочитать книгу Учителя Руана «Введение в стандарты ES6».Обещание-решение ES6 Руана Ифэнаа такжеМини-книга обещаний JavaScript (китайская версия)

  // 组成`Promise`链
  // Hook up interceptors middleware
  // 把 xhr 请求 的 dispatchRequest 和 undefined 放在一个数组里
  var chain = [dispatchRequest, undefined];
  // 创建 Promise 实例
  var promise = Promise.resolve(config);

 // 遍历用户设置的请求拦截器 放到数组的 chain 前面
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

 // 遍历用户设置的响应拦截器 放到数组的 chain 后面
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });

 // 遍历 chain 数组,直到遍历 chain.length 为 0
  while (chain.length) {
    // 两两对应移出来 放到 then 的两个参数里。
    promise = promise.then(chain.shift(), chain.shift());
  }

  return promise;
var promise = Promise.resolve(config);

Объясните это предложение. функция состоит в том, чтобы генерироватьPromiseпример.

var promise = Promise.resolve({name: '若川'})
// 等价于
// new Promise(resolve => resolve({name: '若川'}))
promise.then(function (config){
  console.log(config)
});
// {name: "若川"}

Также объясните, что появится позжеPromise.reject(error);:

Promise.reject(error);
var promise = Promise.reject({name: '若川'})
// 等价于
// new Promise(reject => reject({name: '若川'}))

// promise.then(null, function (config){
//   console.log(config)
// });
// 等价于
promise.catch(function (config){
  console.log(config)
});
// {name: "若川"}

Затем объедините пример, чтобы понять этот код.
К сожалению, вexampleПапки не имеют примера перехватчиков. Автор находится вexampleв серединеexample/getПример перехватчика добавлен поверх .axios/examples/interceptors, который читателям удобно отлаживать.

node ./examples/server.js -p 5000

promise = promise.then(chain.shift(), chain.shift());Этот код достигает точки останова.

Вы получите эту картину.request方法中promise链

Особое внимание справа,localсерединаchainмножество. Это структура.

var chain = [
  '请求成功拦截2', '请求失败拦截2',  
  '请求成功拦截1', '请求失败拦截1',  
  dispatch,  undefined,
  '响应成功拦截1', '响应失败拦截1',
  '响应成功拦截2', '响应失败拦截2',
]

Этот код относительно запутан. То есть будет сгенерирован код, подобный следующему, который будет вызываться в серединеdispatchRequestметод.

// config 是 用户配置和默认配置合并的
var promise = Promise.resolve(config);
promise.then('请求成功拦截2', '请求失败拦截2')
.then('请求成功拦截1', '请求失败拦截1')
.then(dispatchRequest, undefined)
.then('响应成功拦截1', '响应失败拦截1')
.then('响应成功拦截2', '响应失败拦截2')

.then('用户写的业务处理函数')
.catch('用户写的报错业务处理函数');

упомянуть здесьpromise thenа такжеcatchЗнание:
Promise.prototype.thenПервый параметр методаresolvedФункция обратного вызова состояния, второй параметр (необязательный)rejectedФункция обратного вызова статуса. Так что это идет парами.
Promise.prototype.catchпуть.then(null, rejection)или.then(undefined, rejection)Псевдоним для указания функции обратного вызова при возникновении ошибки.
thenметод возвращает новыйPromiseПример (заметьте, не оригинальныйPromiseпример). Поэтому можно использовать метод цепной записи, т.thenПосле вызова метода другогоthenметод.

Если объединить приведенный выше пример более подробно, код будет таким.

var promise = Promise.resolve(config);
// promise.then('请求成功拦截2', '请求失败拦截2')
promise.then(function requestSuccess2(config) {
  console.log('------request------success------2');
  return config;
}, function requestError2(error) {
  console.log('------response------error------2');
  return Promise.reject(error);
})

// .then('请求成功拦截1', '请求失败拦截1')
.then(function requestSuccess1(config) {
  console.log('------request------success------1');
  return config;
}, function requestError1(error) {
  console.log('------response------error------1');
  return Promise.reject(error);
})

// .then(dispatchRequest, undefined)
.then( function dispatchRequest(config) {
  /**
    * 适配器返回的也是Promise 实例
      adapter = function xhrAdapter(config) {
            return new Promise(function dispatchXhrRequest(resolve, reject) {})
      }
    **/
  return adapter(config).then(function onAdapterResolution(response) {
    // 省略代码 ...
    return response;
  }, function onAdapterRejection(reason) {
    // 省略代码 ...
    return Promise.reject(reason);
  });
}, undefined)

// .then('响应成功拦截1', '响应失败拦截1')
.then(function responseSuccess1(response) {
  console.log('------response------success------1');
  return response;
}, function responseError1(error) {
  console.log('------response------error------1');
  return Promise.reject(error);
})

// .then('响应成功拦截2', '响应失败拦截2')
.then(function responseSuccess2(response) {
  console.log('------response------success------2');
  return response;
}, function responseError2(error) {
  console.log('------response------error------2');
  return Promise.reject(error);
})

// .then('用户写的业务处理函数')
// .catch('用户写的报错业务处理函数');
.then(function (response) {
  console.log('哈哈哈,终于获取到数据了', response);
})
.catch(function (err) {
  console.log('哎呀,怎么报错了', err);
});

Посмотрите внимательно на этоPromiseЦепные вызовы, код аналогичный.thenПоследний параметр, возвращаемый методом, является следующимthenПервый параметр метода.
catchОшибка поймать, оба возвращаютсяPromise.reject(error), это для удобства пользователяcatchошибку можно поймать.

Например:

var p1 = new Promise((resolve, reject) => {
 reject(new Error({name: '若川'}));
});

p1.catch(err => {
    console.log(res, 'err');
    return Promise.reject(err)
})
.catch(err => {
 console.log(err, 'err1');
})
.catch(err => {
 console.log(err, 'err2');
});

err2Он не будет захвачен, то есть не будет выполнен, но если оба будут возвращеныreturn Promise.reject(err), его можно захватить.

Наконец, нарисуйте картинку, чтобы подвести итогPromiseцепные вызовы.

axios promise 链式调用

Резюме: 1. Перехватчики запросов и ответов могут быть написаныPromise.
2. Если задано несколько ответчиков на запросы, те, которые установлены позже, будут выполняться первыми.
3. Если установлены перехватчики с несколькими ответами, сначала выполняются те, которые установлены первыми.

dispatchRequest(config)здесьconfigОн возвращается перехватчиком успеха запроса. см. далееdispatchRequestфункция.

5.3. Окончательный запрос на отправку по запросу dispatchRequest.

Эта функция в основном выполняет следующие действия:

1. Если отменяется, тоthrowпривести к ошибкеPromiseкrejected.
2. Убедитесь, чтоconfig.headerсуществует.
3. Преобразование данных с помощью пользовательских преобразователей и преобразователей запросов по умолчанию.
4. Сгладитьconfig.header.
5. Удалите некоторыеconfig.header.
6. Возвратный адаптерadapter(Promiseэкземпляр) после выполненияthenпосле казниPromiseпример. Возвращенный результат передается перехватчику ответов для обработки.

'use strict';
// utils 工具函数
var utils = require('./../utils');
// 转换数据
var transformData = require('./transformData');
// 取消状态
var isCancel = require('../cancel/isCancel');
// 默认参数
var defaults = require('../defaults');

/**
 * 抛出 错误原因,使`Promise`走向`rejected`
 */
function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    config.cancelToken.throwIfRequested();
  }
}

/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 * @returns {Promise} The Promise to be fulfilled
 */
module.exports = function dispatchRequest(config) {
  // 取消相关
  throwIfCancellationRequested(config);

  // Ensure headers exist
  // 确保 headers 存在
  config.headers = config.headers || {};

  // Transform request data
  // 转换请求的数据
  config.data = transformData(
    config.data,
    config.headers,
    config.transformRequest
  );

  // Flatten headers
  // 拍平 headers
  config.headers = utils.merge(
    config.headers.common || {},
    config.headers[config.method] || {},
    config.headers || {}
  );

  // 以下这些方法 删除 headers
  utils.forEach(
    ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
    function cleanHeaderConfig(method) {
      delete config.headers[method];
    }
  );
  // adapter 适配器部分 拆开 放在下文讲
};

5.3.1. Преобразовать данные преобразования данных диспетчерского запроса.

В приведенном выше коде есть функцияtransformData, объяснил здесь. На самом деле, это обход переданного массива функций, работа с данными и, наконец, возврат данных.

axios.defaults.transformResponseПо умолчанию в массиве есть функция, поэтому используйтеconcatСвязать пользовательские функции.

использовать:

Путь к файлуaxios/examples/transform-response/index.html

Этот код на самом деле предназначен для преобразования строки в формате времени в объект времени, который можно вызвать напрямую.getMonthи другие методы.

var ISO_8601 = /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})Z/;
function formatDate(d) {
  return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
}

axios.get('https://api.github.com/users/mzabriskie', {
  transformResponse: axios.defaults.transformResponse.concat(function (data, headers) {
    Object.keys(data).forEach(function (k) {
      if (ISO_8601.test(data[k])) {
        data[k] = new Date(Date.parse(data[k]));
      }
    });
    return data;
  })
})
.then(function (res) {
  document.getElementById('created').innerHTML = formatDate(res.data.created_at);
});

Исходный код:

Это обход массива и вызов передачи в массивеdataа такжеheadersаргументы для вызова функции.

module.exports = function transformData(data, headers, fns) {
  /*eslint no-param-reassign:0*/
  utils.forEach(fns, function transform(fn) {
    data = fn(data, headers);
  });

  return data;
};

5.3.2 Исполнительная часть адаптера адаптера dispatchRequest

Адаптеры называются шаблонами адаптеров в шаблонах проектирования. Расскажите простой пример из жизни, всем легко понять.

Раньше мы использовали разъемы для наушников для мобильных телефонов, которые были круглыми отверстиями, но теперь в основном разъем для наушников и порт для зарядки объединены в один. единый какtypec.

Тогда нам нуженtypec转圆孔的转接口, это адаптер.

  // adapter 适配器部分
  var adapter = config.adapter || defaults.adapter;

  return adapter(config).then(function onAdapterResolution(response) {
    throwIfCancellationRequested(config);

    // Transform response data
    // 转换响应的数据
    response.data = transformData(
      response.data,
      response.headers,
      config.transformResponse
    );

    return response;
  }, function onAdapterRejection(reason) {
    if (!isCancel(reason)) {
      // 取消相关
      throwIfCancellationRequested(config);

      // Transform response data
      // 转换响应的数据
      if (reason && reason.response) {
        reason.response.data = transformData(
          reason.response.data,
          reason.response.headers,
          config.transformResponse
        );
      }
    }

    return Promise.reject(reason);
  });

Далее смотрите конкретноadapter.

5.4 адаптер Адаптер действительно отправляет запрос

var adapter = config.adapter || defaults.adapter;

прочитайте вышеadapter, вы можете знать, что поддерживается настройка пользователя. Например, через апплет WeChatwx.requestТакже напишитеadapter.
Тогда взглянитеdefaults.ddapter.
Путь к файлу:axios/lib/defaults.js

Вводится в соответствии с текущей средой, если она вводится в среде браузера.xhr,Даnodeвводится средаhttp.
Аналогичное суждениеnodeсреда, а такжеsentry-javascriptСм. исходный код.

function getDefaultAdapter() {
  var adapter;
  // 根据 XMLHttpRequest 判断
  if (typeof XMLHttpRequest !== 'undefined') {
    // For browsers use XHR adapter
    adapter = require('./adapters/xhr');
    // 根据 process 判断
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    // For node use HTTP adapter
    adapter = require('./adapters/http');
  }
  return adapter;
}
var defaults = {
  adapter: getDefaultAdapter(),
  // ...
};

xhr

Дальше то, что нам знакомоXMLHttpRequestобъект.

Может быть, читатели не понимают, вы можете обратиться кXMLHttpRequest Документация MDN.

Главное напоминание:onabortзапрос на отмену мероприятия,withCredentialsэто логическое значение, используемое для указания междоменногоAccess-ControlДолжен ли запрос содержать информацию об авторизации, такую ​​какcookieили уполномоченныйheaderголова.

Этот код был удален, вы можете посмотреть подробностиВакагавыaxios-analysisсклад, так же можно клонировать автораaxios-analysisДетальный анализ будет сделан, когда склад будет отлажен.

module.exports = function xhrAdapter(config) {
  return new Promise(function dispatchXhrRequest(resolve, reject) {
    // 这块代码有删减
    var request = new XMLHttpRequest();
    request.open()
    request.timeout = config.timeout;
    // 监听 state 改变
    request.onreadystatechange = function handleLoad() {
      if (!request || request.readyState !== 4) {
        return;
      }
      // ...
    }
    // 取消
    request.onabort = function(){};
    // 错误
    request.onerror = function(){};
    // 超时
    request.ontimeout = function(){};
    // cookies 跨域携带 cookies 面试官常喜欢考这个
    // 一个布尔值,用来指定跨域 Access-Control 请求是否应带有授权信息,如 cookie 或授权 header 头。
    // Add withCredentials to request if needed
    if (!utils.isUndefined(config.withCredentials)) {
      request.withCredentials = !!config.withCredentials;
    }

    // 上传下载进度相关
    // Handle progress if needed
    if (typeof config.onDownloadProgress === 'function') {
      request.addEventListener('progress', config.onDownloadProgress);
    }

    // Not all browsers support upload events
    if (typeof config.onUploadProgress === 'function' && request.upload) {
      request.upload.addEventListener('progress', config.onUploadProgress);
    }

    // Send the request
    // 发送请求
    request.send(requestData);
  });
}

А на самом деле сейчасfetchПоддержка очень хорошая, Али с открытым исходным кодомumi-requestЗапросите библиотеку, просто используйтеfetchинкапсулированный, вместо использованияXMLHttpRequest. В конце статьи примерноumi-requestа такжеaxiosразница.

http

httpЗдесь он не будет подробно описываться, и заинтересованные читатели могут ознакомиться с ним самостоятельно.Вакагавыaxios-analysisсклад.

module.exports = function httpAdapter(config) {
  return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
  });
};

надdispatchRequestЕсть модуль отмены, который я считаю ключевым моментом, поэтому подробно расскажу о нем в конце:

5.5 Модуль отмены dispatchRequest

можно использоватьcancel tokenОтмените запрос.

axios API отмены токена основан на отзывеpromiseОтменить предложение.

The axios cancel token API is based on the withdrawn cancelable promises proposal.

отмена документации axios

Оба варианта использования подробно описаны в документации.

К сожалению, вexampleПапки также не имеют примера отмены. Автор находится вexampleв серединеexample/getДобавлен отмененный пример на основе .axios/examples/cancel, который читателям удобно отлаживать.

node ./examples/server.js -p 5000

requestПерехватчики в иdispatchОтмена этих двух модулей относительно сложна, и ее можно отладить и переварить.

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/get/server', {
  cancelToken: source.token
}).catch(function (err) {
  if (axios.isCancel(err)) {
    console.log('Request canceled', err.message);
  } else {
    // handle error
  }
});

// cancel the request (the message parameter is optional)
// 取消函数。
source.cancel('哎呀,我被若川取消了');

5.5.1 Пример кода модуля запроса на отмену

В сочетании с процессом отмены исходного кода, вероятно, это так. Вставьте этот код вaxios/examples/cancel-token/index.html.

параметрическийconfig.cancelTokenсрабатываетsource.cancel('哎呀,我被若川取消了');только что сгенерированный.

// source.cancel('哎呀,我被若川取消了');
// 点击取消时才会 生成 cancelToken 实例对象。
// 点击取消后,会生成原因,看懂了这段在看之后的源码,可能就好理解了。
var config = {
  name: '若川',
  // 这里简化了
  cancelToken: {
        promise: new Promise(function(resolve){
            resolve({ message: '哎呀,我被若川取消了'})
        }),
        reason: { message: '哎呀,我被若川取消了' }
  },
};
// 取消 抛出异常方法
function throwIfCancellationRequested(config){
  // 取消的情况下执行这句
  if(config.cancelToken){
    //   这里源代码 便于执行,我改成具体代码
    // config.cancelToken.throwIfRequested();
    // if (this.reason) {
    //     throw this.reason;
    //   }
    if(config.cancelToken.reason){
        throw config.cancelToken.reason;
    }
  }
}

function dispatchRequest(config){
  // 有可能是执行到这里就取消了,所以抛出错误会被err2 捕获到
  throwIfCancellationRequested(config);
  //  adapter xhr适配器
  return new Promise((resovle, reject) => {
    var request = new XMLHttpRequest();
    console.log('request', request);
    if (config.cancelToken) {
        // Handle cancellation
        config.cancelToken.promise.then(function onCanceled(cancel) {
            if (!request) {
                return;
            }

            request.abort();
            reject(cancel);
            // Clean up request
            request = null;
        });
    }
  })
  .then(function(res){
    // 有可能是执行到这里就才取消 取消的情况下执行这句
    throwIfCancellationRequested(config);
    console.log('res', res);
    return res;
  })
  .catch(function(reason){
    // 有可能是执行到这里就才取消 取消的情况下执行这句
    throwIfCancellationRequested(config);
    console.log('reason', reason);
    return Promise.reject(reason);
  });
}

var promise = Promise.resolve(config);

// 没设置拦截器的情况下是这样的
promise
.then(dispatchRequest, undefined)
// 用户定义的then 和 catch
.then(function(res){
  console.log('res1', res);
  return res;
})
.catch(function(err){
  console.log('err2', err);
  return Promise.reject(err);
});
// err2 {message: "哎呀,我被若川取消了"}

5.5.2 Далее смотрим исходный код модуля отмены

посмотреть, как сгенерироватьconfig.cancelToken.

Путь к файлу:

axios/lib/cancel/CancelToken.js

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
source.cancel('哎呀,我被若川取消了');

посмотреть на примереCancelToken.sourceреализация,

CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  // token
  return {
    token: token,
    cancel: cancel
  };
};

после казниsourceПримерная структура такая.

{
    token: {
    promise: new Promise(function(resolve){
      resolve({ message: '哎呀,我被若川取消了'})
    }),
    reason: { message: '哎呀,我被若川取消了' }
  },
  cancel: function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      // 已经取消
      return;
    }
    token.reason = {message: '哎呀,我被若川取消了'};
  }
}

см. далееnew CancelToken

// CancelToken
// 通过 CancelToken 来取消请求操作
function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      // 已经取消
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

module.exports = CancelToken;

Это то, что используется в адаптере, который отправляет запрос.

// xhr
if (config.cancelToken) {
  // Handle cancellation
  config.cancelToken.promise.then(function onCanceled(cancel) {
    if (!request) {
      return;
    }

    request.abort();
    reject(cancel);
    // Clean up request
    request = null;
  });
}

dispatchRequestсерединаthrowIfCancellationRequestedКонкретная реализация: throw выдает исключение.

// 抛出异常函数
function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    config.cancelToken.throwIfRequested();
  }
}
// 抛出异常 用户 { message: '哎呀,我被若川取消了' }
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

отменить стек вызовов процесса

1.source.cancel()
2.resolvePromise(token.reason);
3.config.cancelToken.promise.then(function onCanceled(cancel) {})

последняя записьrequest.abort();``reject(cancel);

Здесь представлен процесс отмены. В основном путем передачи параметров конфигурацииcancelToken, будет генерироваться только при отменеcancelToken, судя есть, кинь ошибку, чтобPromiseкrejected, позвольте пользователю захватить сообщение {сообщение: 'информация об отмене, установленная пользователем'}.

Статья в основном написана здесь до конца.

Если ты дочитал до конца, значит, ты превзошел многих ^_^

axiosЭто очень хорошая библиотека запросов, но она определенно не может удовлетворить потребности всех разработчиков.Далее сравните другие библиотеки, чтобы увидеть, какие конкретные потребности есть у других разработчиков.

6. Сравните с другими библиотеками запросов

6.1 KoAjax

Лидер сообщества FCC Chengdu Shuige с открытым исходным кодомKoAJAX.

Как использовать ПО с открытым исходным кодом для проведения технической конференции?Выдержка из статьи ниже.

Библиотека внешних запросов — KoAJAX Наиболее часто используемой библиотекой HTTP-запросов для домашних студентов, изучающих интерфейс, должна быть axios, верно? Хотя его Interceptor API называется .use(), он полностью отличается от промежуточного режима Node.js Express, Koa и др. По сравнению с jQuery.ajaxPrefilter() и dataFilter() существенных улучшений нет; прогресс загрузки проще, чем jQuery.Deferred(), всего две специальные опции обратного вызова. Поэтому ему все равно приходится запоминать конкретные API для конкретных требований, что недостаточно лаконично.

К счастью, Water Song работает над тем, какРеализация движка промежуточного программного обеспечения, подобного Koa, с асинхронными итераторами ES 2018В процессе было создано более практичное приложение верхнего уровня — KoAJAX. Весь его процесс выполнения основан на промежуточном программном обеспечении в стиле Koa, и сам он является стеком вызовов промежуточного программного обеспечения. В дополнение к сокращенным методам, таким как .get(), .post(), .put() и .delete(), обычно используемым в RESTful API, разработчикам нужно помнить только .use() и next(), остальные являются стандартами ES Syntax и выводом типа TS.

6.2 umi-request Библиотека запросов Alibaba с открытым исходным кодом

репозиторий umi-request на github

umi-requestа такжеfetch, axiosСходства и различия.

umi-request 与 fetch, axios 异同

должен сказать,umi-requestОн действительно мощный, и заинтересованные читатели могут прочитать его исходный код.

пониматьaxiosна основе пониманияumi-requestИсходный код не должен быть сложным.

Напримерumi-requestРазблокировка кода модуля практически аналогичнаaxiosТочно так же.

7. Резюме

Подробности статьиaxiosМетод отладки. подробныйaxiosРеализация таких функций, как конструкторы, перехватчики, отмены и т. д. Наконец, сравниваются другие библиотеки запросов.

Наконец, нарисуйте картинку, чтобы обобщить общий процесс аксиом.

axios的总体大致流程

Ответьте на вопросы, заданные в начале статьи:

Если вы ищете работу, проект написан и используетсяaxios, интервьюер может спросить вас:

1. ПочемуaxiosЕго можно использовать как в качестве вызова функции, так и в качестве объекта, напримерaxios({}),axios.get.

отвечать:axiosСуть - это функция, и назначаются некоторые методы-псевдонимы, такие какget,postМетод может быть вызван, и окончательный вызов по-прежнемуAxios.prototype.requestфункция.

2. Краткое описаниеaxiosпроцесс вызова.

Ответ: на самом деле называетсяAxios.prototype.requestметод, окончательный результатpromiseСцепленные вызовы, фактический запрос находится вdispatchRequestраспространяется в.

3. Вы когда-нибудь использовали перехватчик? Каков принцип?

Ответ: б/у, б/уaxios.interceptors.request.useДобавьте функции перехватчика успешных и неудачных запросов сaxios.interceptors.response.useДобавьте функции перехватчика успешного и неудачного ответа. существуетAxios.prototype.requestфункциональная композицияpromiseПри объединении вызововInterceptors.protype.forEachДобавлены перехватчики запроса и ответа для фактической отправки запроса.dispatchRequestОба конца запроса, чтобы обеспечить перехват до запроса и перехват после ответа. Перехватчики также поддерживают использованиеInterceptors.protype.ejectметод удален.

4. Используйтеaxiosфункция отмены? Как это достигается?

A: Используется, проходя мимоconfigнастроитьcancelTokenформу для отмены. СуждениеcancelToken,существуетpromiseприкованныйdispatchRequestвыдает ошибку наadapterсерединаrequest.abort()отменить запросpromiseкrejected, информация об отмене фиксируется пользователем.

5. Почему он поддерживает отправку запросов в браузерах?nodeпослать запрос?

отвечать:axios.defaults.adapterВ конфигурации по умолчанию браузер или среда оцениваются в соответствии со средой.nodeсреде используйте соответствующий адаптер. Адаптер поддерживает настройку.

Чтобы ответить на вопросы интервьюера, читатели также могут организовать язык в соответствии со своим пониманием Ответ автора только для справки.

axiosИсходный код относительно небольшой, более тысячи строк после упаковки, его относительно легко читать, и его очень стоит изучить.

предложениеclone GitHub-репозиторий аксиального анализа Вакагавы, отлаживайте сами по методике в тексте, а мне больше импонирует.

на основеPromise, составляютPromiseЦепочка, ловко настройте перехват запроса, отправьте запрос и снова попробуйте перехватчик ответа.

requestПерехватчики в иdispatchОтмена этих двух модулей относительно сложна, и ее можно отладить и переварить.

axiosЭто функция, когда это функция, вызовAxios.prototype.requestфункция, которая также является объектом, на которомget,postДождитесь метода запроса и, наконец, вызовитеAxios.prototype.requestфункция.

axiosВ исходном коде используется множество шаблонов проектирования. Например, заводской режим, режим итератора, режим адаптера и т. д. Если вы хотите систематически изучать шаблоны проектирования, обычно рекомендуется иметь показатель Доубана 9,1.Шаблоны проектирования JavaScript и практика разработки

Если читатель обнаружит что-то неправильное или что-то, что можно улучшить, или где это неясно написано, пожалуйста, прокомментируйте и укажите. Кроме того, я чувствую, что написание хорошее, и это немного полезно для вас.Вы можете ставить лайки, комментировать, пересылать и делиться, что также является своего рода поддержкой для автора.Большое спасибо.

Рекомендуемое чтение

Официальный репозиторий axios на github

Прежде чем написать статью, я искал и читал следующие статьи. Заинтересованы в сравнении следующих статей, основанных на отладке кода, это выглядит быстро.

Я всегда чувствую, что поиск еще нескольких статей полезнее для получения знаний. Есть такое понятие, как тематическое чтение. Это, вероятно, означает серию чтений по теме.

@Позвони мне Сяомин: анализ исходного кода Axios
@NikuNikusan: объясните исходный код axios простым языком
@小thief Mr. _ronffy: Углубленный анализ исходного кода Axios — новый король AJAX
Построчный разбор исходного кода Axios
Как Axios инкапсулирует HTTP-запросы
Знакомство с @Lee: рефакторинг TypeScript Обмен опытом Axios

Очередная серия автора

Интервьюер спросил: наследование JS
Интервьюер спросил: этот пункт JS
Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?

о

Автор: Чанг ИВакагаваНазвание смешано в реках и озерах. По дороге на фронт | Энтузиасты РРТ | Знаю очень мало, только хорошо учусь.
Блог Вакагавы,использоватьvuepressРефакторинг, опыт чтения может быть лучше
Колонка самородков, добро пожаловать, обратите внимание~
segmentfaultПередняя колонка обзора, добро пожаловать, обратите внимание~
Знайте переднюю колонку видения, добро пожаловать, обратите внимание~
github blog, соответствующий исходный код и ресурсы размещены здесь, попросите одинstar^_^~

Добро пожаловать, чтобы добавить общедоступную учетную запись WeChat для общения в WeChat

Может быть более интересным общедоступный аккаунт WeChat, нажмите и удерживайте, чтобы отсканировать код, чтобы следовать. Добро пожаловать, чтобы добавить автора WeChatruochuan12(Укажите источник, в основном никто не будет отклонен), пригласите вас в [Группу обмена видением переднего плана] для долгосрочного обмена и обучения ~