Статьи, изначально опубликованные на сайте TutorialDocsКак реализовать библиотеку HTTP-запросов с помощью Axios.
Обзор
Во фронтенд-разработке часто встречается сцена отправки асинхронных запросов. Полнофункциональная библиотека HTTP-запросов может значительно сократить наши затраты на разработку и повысить ее эффективность.
axios — это такая библиотека HTTP-запросов, которая стала очень популярной в последние годы. В настоящее время он имеет более 40 000 звезд на GitHub и рекомендуется многими экспертами.
Поэтому нам необходимо понять, как устроен axios и как реализовать инкапсуляцию библиотеки HTTP-запросов. На момент написания текущая версия axios — 0.18.0, и мы используем эту версию в качестве примера для чтения и анализа части основного исходного кода. Все исходные файлы для axios находятся вlib
папка, указанные ниже пути относятся кlib
Говоря о.
В этой статье мы в основном обсуждаем:
-
Как использовать аксиомы.
-
Как разработаны и реализованы основные модули axios (запрос, перехватчик, отзыв)?
-
Каковы конструктивные преимущества axios?
Как использовать аксиомы
Чтобы понять структуру аксиом, сначала нужно посмотреть, как использовать аксиомы. Давайте возьмем простой пример, чтобы проиллюстрировать использование axios API.
послать запрос
axios({
method:'get',
url:'http://bit.ly/2mTM3nY',
responseType:'stream'
})
.then(function(response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
Это официальный пример. Как видно из приведенного выше кода, использование Axios связано с jQuery.ajax
Методы очень похожи, оба возврата объекта обещания (возможности успеха также могут быть использованы здесь, но все еще более рекомендуемыеPromise
илиawait
), прежде чем продолжить.
Этот пример настолько прост, что мне не нужно его объяснять. Давайте посмотрим, как добавить функцию-перехватчик.
Добавить функцию перехватчика
// 添加一个请求拦截器。注意,这里面有 2 个函数——分别是成功和失败时的回调函数,这样设计的原因会在之后介绍
axios.interceptors.request.use(function (config) {
// 发起请求前执行一些处理任务
return config; // 返回配置信息
}, function (error) {
// 请求错误时的处理
return Promise.reject(error);
});
// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
// 处理响应数据
return response; // 返回响应数据
}, function (error) {
// 响应出错后所做的处理工作
return Promise.reject(error);
});
Из приведенного выше кода мы можем узнать: Перед отправкой запроса мы можем настроить параметры запроса (config
) для обработки; после ответа на запрос мы можем обработать возвращенные данные. Когда запрос или ответ терпят неудачу, мы также можем указать соответствующую функцию обработки ошибок.
Отозвать HTTP-запрос
При разработке модулей, связанных с поиском, нам часто приходится часто отправлять запросы на получение данных. В общем, когда мы отправляем следующий запрос, нам нужно отозвать предыдущий запрос. Поэтому возможность отозвать связанные запросы очень полезна. Пример кода для запроса отзыва axios выглядит следующим образом:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
// 例子一
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('请求撤销了', thrown.message);
} else {
// 处理错误
}
});
// 例子二
axios.post('/user/12345', {
name: '新名字'
}, {
cancelToken: source.token
}).
// 撤销请求 (信息参数是可选的)
source.cancel('用户撤销了请求');
Как вы можете видеть из приведенного выше примера, в axios, используяCancelToken
схема запроса на вывод средств. Однако сейчас это предложение было отозвано, как указано вкликните сюда. Конкретный метод реализации запроса на отзыв будет объяснен позже при анализе исходного кода.
Дизайн и реализация основного модуля axios
Благодаря приведенным выше примерам я считаю, что у всех есть общее представление об использовании аксиом. Ниже мы проанализируем дизайн и реализацию axios с точки зрения модулей. На картинке ниже показан файл исходного кода, который я представлю в этой статье. Если вы заинтересованы, лучше всего клонировать соответствующий код во время чтения, это углубит ваше понимание соответствующего модуля.
Модуль HTTP-запроса
Код модуля запроса находится вcore/dispatchRequest.js
В файле здесь я показываю только некоторые коды клавиш, чтобы кратко объяснить:
module.exports = function dispatchRequest(config) {
throwIfCancellationRequested(config);
// 其他源码
// 默认适配器是一个模块,可以根据当前环境选择使用 Node 或者 XHR 发送请求。
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// 其他源码
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// 其他源码
return Promise.reject(reason);
});
};
В приведенном выше коде мы можем знатьdispatchRequest
метод черезconfig.adapter
, получить модуль отправки запроса. Мы также можем заменить исходный модуль, передав соответствующую спецификации функцию адаптера (обычно мы этого не делаем, но это слабосвязанная точка расширения).
существуетdefaults.js
В файле мы видим логику выбора соответствующего адаптера — какой адаптер использовать на основе некоторых уникальных свойств и конструкторов текущего контейнера.
function getDefaultAdapter() {
var adapter;
// 只有在 Node.js 中包含 process 类型对象时,才使用它的请求模块
if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// Node.js 请求模块
adapter = require('./adapters/http');
} else if (typeof XMLHttpRequest !== 'undefined') {
// 浏览器请求模块
adapter = require('./adapters/xhr');
}
return adapter;
}
Модуль XHR в axios относительно прост, онXMLHTTPRequest
Инкапсуляция объекта, я не буду объяснять это здесь. Заинтересованные студенты, вы можете сами прочитать исходный код, исходный код находится по адресуadapters/xhr.js
в файле.
модуль-перехватчик
Теперь давайте посмотрим, как axios обрабатывает функции перехватчика запросов и ответов. Это связано с унифицированным интерфейсом в axios -request
функция.
Axios.prototype.request = function request(config) {
// 其他源码
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Эта функция является интерфейсом для отправки запросов axios. Поскольку код реализации функции довольно длинный, здесь я кратко расскажу о соответствующих дизайнерских идеях:
-
chain
является очередью выполнения. Начальное значение очереди — это конфигурация переноса (config
) параметр объекта Promise. -
В очереди выполнения исходная функция
dispatchRequest
используется для отправки запросов, для связи сdispatchRequest
Соответственно добавляемundefined
. Добавить кundefined
Причина в том, что вам нужно предоставить функции обратного вызова для успеха и неудачи Promise из следующего кодаpromise = promise.then(chain.shift(), chain.shift());
Мы видим, что. Следовательно, функцияdispatchRequest
а такжеundefiend
Его можно рассматривать как пару функций. -
в очереди на выполнение
chain
, который отправил запросdispatchReqeust
Функция находится посередине. Ему предшествует перехватчик запросов, использующийunshift
вставка метода; за ним следует перехватчик ответа, использующийpush
способ вставки, вdispatchRequest
Позже. Следует отметить, что все эти функции являются парными, то есть одновременно будут вставлены две.
просматривать вышеrequest
Код функции, мы примерно умеем пользоваться перехватчиками. Далее давайте посмотрим, как отозвать HTTP-запрос.
модуль запроса на отзыв
Модули, связанные с запросами на вывод средств, находятся по адресуCancel/
Под папкой теперь давайте посмотрим на соответствующий основной код.
Сначала рассмотрим основыCancel
Добрый. Это класс, используемый для записи статуса отзыва. Конкретный код выглядит следующим образом:
function Cancel(message) {
this.message = message;
}
Cancel.prototype.toString = function toString() {
return 'Cancel' + (this.message ? ': ' + this.message : '');
};
Cancel.prototype.__CANCEL__ = true;
использоватьCancelToken
class, вам нужно передать ему метод Promise для реализации отзыва HTTP-запроса Конкретный код выглядит следующим образом:
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) {
// 已经被撤销了
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
adapters/xhr.js
В файле место для отзыва запроса прописано так:
if (config.cancelToken) {
// 等待撤销
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// 重置请求
request = null;
});
}
В приведенном выше примере отзыва HTTP-запроса давайте кратко обсудим соответствующую логику реализации:
-
В запросе, который необходимо отозвать, звоните
CancelToken
Категорияsource
Класс метода инициализируется и получит содержащийCancelToken
экземпляр класса A иcancel
объект метода. -
Пока исходный метод возвращает экземпляр A, состояние ожидания
promise
Инициализация объекта завершена. После передачи экземпляра A в axios,promise
Его можно использовать как триггер для отмены запроса. -
при вызове через
source
метод возвращенcancel
метод, в примере Apromise
Статус меняется с "ожидание" на "выполнено", а затем срабатывает немедленно.then
Перезвоните. Итак, метод отмены axios——request.abort()
был запущен.
Каковы преимущества этой конструкции axios?
Логика обработки функции отправки запроса
Как упоминалось в предыдущих главах, axios не будут использоваться для отправки запросов.dispatchRequest
Функция рассматривается как специальная функция. Фактически,dispatchRequest
Он будет помещен в середину очереди, чтобы обеспечить согласованность обработки очереди и удобочитаемость кода.
Логика обработки адаптера
В логике обработки адаптераhttp
а такжеxhr
Модуль (один используется в node.js для отправки запросов, один не в браузере для отправки запроса) неdispatchRequest
функция, но каждый как отдельный модуль, по умолчаниюdefaults.js
Вводится методом конфигурации в файле. Таким образом, он не только обеспечивает низкую связь между двумя модулями, но и предоставляет будущим пользователям пространство для настройки модуля отправки запросов.
Логика отзыва HTTP-запросов
В логике отмены HTTP-запросов axios предназначен для использования промисов в качестве триггеров, которыеresolve
Функция выставляется и используется в функции обратного вызова. Это не только обеспечивает согласованность внутренней логики, но также гарантирует, что при отзыве запроса выборочные данные соответствующего класса не нужно изменять напрямую, чтобы в значительной степени избежать взлома других модулей.
Суммировать
В этой статье подробно рассказывается об использовании, дизайнерских идеях и методах реализации аксиом. После прочтения вы сможете понять структуру axios, а также понять инкапсуляцию и взаимодействие модулей.
В этой статье представлены только основные модули axios.Если вас интересуют коды других модулей, вы можете перейти наGitHubПосмотреть выше.
(над)