Сцены:
Как разработчики, мы больше всего подвержены CRUD, совместной отладке различных интерфейсов, но, похоже, меньше внимания будем уделять отправляемым http запросам, когда этот запрос не выполняется и отправляется новый запрос, то текущий How должен быть обработан запрос? Мы знаем, что для предотвращения повторных действий можно использовать аналогичный антишейк и троттлинг, чтобы избежать, но сегодня мы поговорим о том, как избежать повторных запросов с уровня запроса, а не блокировки со стороны пользователя. На самом деле попыток разработчиков в этой области в интернете тоже много, но некоторые из них не столь однозначны. С этой целью, после изучения некоторых знаний в этой области, в сочетании со сценами, с которыми я обычно сталкиваюсь в разработке. Обобщите два наиболее распространенных сценария, в которых необходимо отменить HTTP-запросы.
сцена первая:
Тот же запрос должен быть отменен. Тот же запрос здесь означает, что для запроса на получение используется тот же метод, те же параметры и тот же URL-адрес. Для запроса Post, конечно, метод то же самое, тело такое же, и URL тот же.
Сценарий второй:
Адрес маршрутизации изменился (предыдущий запрос веб-страницы не имеет смысла)
Реализация:
Прежде всего, чтобы добиться повторной отмены, нам нужно сделать два шага: первый шаг — узнать, как отменить, а второй шаг — определить, является ли текущий запрос дубликатом.
Метод реализации отмены повторного запроса:
Что касается отмены, я объясню эту часть с двух аспектов axios и fetch, потому что методы реализации отмены для этих двух методов запроса различны.
Чтобы облегчить понимание, мы используем react для более прямой демонстрации этого процесса, потому что мы знаем, что функция ловушки useEffect, характеристики useEffect определяют, что функция возврата будет выполняться один раз перед выполнением каждого useEffect для очистки, поэтому здесь, ставим Здесь размещена операция отмены, можно каждый раз имитировать отмену предыдущей операции
axios
Прежде всего, мы введем axios.Этот интерфейс обязательно выплюнет его.В одном предложении суть axios для достижения отмены заключается в использовании его внутренне инкапсулированного CancelToken.
Во-первых, нужно знать, что токен определяет уникальность, которая также является идентификацией того, какой запрос нужно отменить, его можно сгенерировать с помощью метода cancelToken.source().
source содержит метод отмены, мы вызываем его для отмены
useEffect(() => {
const cancelToken = axios.CancelToken;
const source = cancelToken.source();
setAxiosRes("axios request created");
getReq(source).then((res) => {
setAxiosRes(res);
});
return () => {
source.cancel("axios request cancelled");
};
}, [axiosClick]);
export const instance = axios.create({
baseURL: "http://localhost:4001",
});
export const getReq = async (source) => {
try {
const {
data
} = await instance.get("/", {
cancelToken: source.token,
});
return data;
} catch (err) {
if (axios.isCancel(err)) {
return "axios request cancelled";
}
return err;
}
};
Здесь следует отметить, что само действие отмены может быть захвачено частью catch, и оно также является ошибкой. Мы используем предоставленный им метод isCancel, чтобы определить, является ли это операцией отмены. Это можно использовать для проверки того, является ли наша отмена была успешной или нет.
fetch:
Тогда ситуация выборки другая.Реализация выборки заключается в отмене через сигнал.Его внутренний AbortController() может отменить все запросы, которые отвечают на сигнальную метку.Также один раз моделируется с реакцией.На самом деле суть еще та то же самое, и его тоже можно поймать
export const instance = axios.create({
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
setFetchRes("fetch request created");
hitApi(signal).then((res) => {
setFetchRes(res);
});
//cleanup function
return () => {
controller.abort();
};
}, [fetchClick]);
Функция hitApi заключается в следующем, то есть поместите сигнал в нашу выборку, чтобы мы могли прервать ее.
export const hitApi = async (signal) => {
try {
const response = await fetch("http://localhost:4001/", {
signal
});
const data = await response.json();
return data;
} catch (err) {
if (err.name === "AbortError") {
return "Request Aborted ";
}
return err;
}
}
То же самое здесь, 'AbortError' может быть пойман в catch
Определите, следует ли повторять
Что ж, функция отмены реализована, а дальше надо подумать, как определить, повторяется ли запрос. Нет сомнения, что для определения повторяется ли он, если вы хотите, чтобы временная сложность постоянного уровня нашла, есть ли повторяющийся запрос, конечно, используйте Map, чтобы вы могли найти повторяющийся запрос со скоростью O(1 ), чтобы вы могли принять решение об отмене. Более того, вполне возможно, что весь процесс должен добавлять элементы в массив, и, конечно, те, которые были отменены, должны быть удалены, поэтому нам нужны функция добавления и функция удаления.
const addPending = (config) => {
const url = [
config.method,
config.url,
qs.stringify(config.params),
qs.stringify(config.data)
].join('&')
config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
if (!pending.has(url)) { // If the current request does not exist in pending, add it
pending.set(url, cancel)
}
})
}
При присвоении значения config.cancelToken следует обратить внимание на то, имеет ли уже значение текущий config.cancelToken
Чтобы упростить наши параметры тайлинга, мы можем использовать qs для преобразования объекта в строку.
const removePending = (config) => {
const url = [
config.method,
config.url,
qs.stringify(config.params),
qs.stringify(config.data)
].join('&')
if (pending.has(url)) { // If the current request identity exists in pending, you need to cancel the current request and remove it
const cancel = pending.get(url)
cancel(url)
pending.delete(url)
}
}
аксиальный перехватчик
Однако в реальных проектах у нас обычно есть перехватчики axios для унифицированного управления нашими запросами, поэтому здесь есть много людей, которым нравится добавлять эти два метода непосредственно в перехватчики axios, чтобы это было сделано раз и навсегда.
axios.interceptors.request.use(config => {
removePending(options) // Check previous requests to cancel before the request starts
addPending(options) // Add current request to pending
// other code before request
return config
}, error => {
return Promise.reject(error)
})
axios.interceptors.response.use(response => {
removePending(response) // Remove this request at the end of the request
return response
}, error => {
if (axios.isCancel(error)) {
console.log('repeated request: ' + error.message)
} else {
// handle error code
}
return Promise.reject(error)
})
Как использовать коммутатор маршрутизации
Наконец, давайте поговорим о втором сценарии, ситуации, когда маршрут переключается, это относительно просто, просто очистите нашу очередь ожидания напрямую, просто напрямую:
export const clearPending = () => {
for (const [url, cancel] of pending) {
cancel(url)
}
pending.clear()
}
router.beforeEach((to, from, next) => {
clearPending()
// ...
next()
})
Демонстрация эффекта:
Как вы можете видеть, если вы нажмете несколько раз, запрос будет отменен, и если он будет успешно возвращен, это будет 200.
Принципиальный анализ:
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(cancel方法);
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
//token.reason是Cancel的实例
token.reason = new Cancel(message);
resolvePromise(token.reason);//改变promise的状态
});
}
По сути, суть CancelToken — монтировать промис, а затем не активно разрешать или отклонять, а сначала выставлять инициативу, то есть resolvePromise в коде, а затем менять промис в статусе отмененной функции.
Какая польза от изменения этого состояния? Это нужно понимать в сочетании с исходным кодом xhrAdapter. Здесь мы можем видеть, где прерывание. Красная часть — это процесс изменения состояния обещания через вышеизложенное, и процесс выполняется в .then.
function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
if (config.cancelToken) {
//请求中,监听cancelToken中promise状态改变
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
request = null;
});
}
})
}
Заключение:
На самом деле отмена http запроса не очень необычна.Для достижения аналогичной отмены запроса есть много других способов и даже много способов лучше этого.Например отмена текущего запроса вместо отмены предыдущего,кажется более логично, но в этой статье основное внимание уделяется идее разоблачения решимости, которой стоит научиться.
Текст/Лили
Обратите внимание на Dewu Technology и станьте самым модным техническим специалистом!