Вопрос проверяет понимание проблемы состояния гонки (race condition) при асинхронных запросах из поля ввода и способов её решения.
Когда пользователь быстро печатает в поле ввода, каждый символ может инициировать асинхронный запрос к серверу (например, для автодополнения). Из-за разного времени обработки ответы могут прийти не в том порядке, в котором были отправлены запросы. Это называется race condition: более старый запрос может завершиться позже и перезаписать актуальные данные от более нового запроса.
let lastRequestId = 0;
input.addEventListener('input', async () => {
const requestId = ++lastRequestId;
const response = await fetch(`/search?q=${input.value}`);
const data = await response.json();
if (requestId === lastRequestId) {
// Только если это последний запрос
displayResults(data);
}
});Здесь мы используем счётчик lastRequestId, чтобы проверять, является ли ответ актуальным. Если пришёл ответ от старого запроса, он игнорируется.
Debounce — это техника, которая откладывает выполнение функции до тех пор, пока не пройдёт определённое время после последнего вызова. Это уменьшает количество запросов и предотвращает race condition.
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
const search = debounce(async (query) => {
const response = await fetch(`/search?q=${query}`);
const data = await response.json();
displayResults(data);
}, 300);
input.addEventListener('input', (e) => search(e.target.value));Теперь запрос отправляется только через 300 мс после того, как пользователь перестал печатать. Это снижает нагрузку и исключает race condition, так как предыдущий запрос уже не отправляется.
Современный подход — отменять предыдущий запрос с помощью AbortController. Это особенно полезно, если запросы могут быть долгими.
let controller;
input.addEventListener('input', async () => {
if (controller) controller.abort();
controller = new AbortController();
try {
const response = await fetch(`/search?q=${input.value}`, {
signal: controller.signal
});
const data = await response.json();
displayResults(data);
} catch (err) {
if (err.name !== 'AbortError') throw err;
}
});При каждом новом вводе предыдущий запрос отменяется, что гарантирует актуальность данных.
Для решения race condition при отправке запросов из input используйте комбинацию debounce для уменьшения частоты запросов и AbortController для отмены устаревших запросов. Это обеспечивает корректное отображение данных и улучшает производительность.
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию