> Как предотвратить двойной заказ при двойном клике на кнопку? (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: sferaplatform.ru

Стек: JavaScript

> Пример ответа

Короткий ответ

Основные подходы: блокировка кнопки после первого клика (disabled), debounce с отменой повторных вызовов, использование флага-блокировки (lock flag) или idempotency key на стороне сервера. Для frontend-решения достаточно отключать кнопку в обработчике и включать после ответа сервера или ошибки. Важно учитывать асинхронность - снимать блокировку только в finally, а не в then/catch по отдельности.

Подробное объяснение

Двойной заказ возникает из-за того, что клиент отправляет несколько одинаковых запросов до получения ответа от сервера. На фронтенде это решается несколькими способами:

  1. Отключение кнопки (disabled) - самый простой и надёжный способ. После первого клика кнопка становится неактивной до завершения операции.

  2. Debounce/throttle - ограничение частоты вызовов, но не гарантирует защиту от двойного заказа при быстрых кликах.

  3. Флаг-блокировка - переменная isProcessing, которая проверяется в начале обработчика. Подходит для случаев, когда кнопку нельзя отключать визуально.

  4. Idempotency key - передача уникального ключа в запросе, сервер обрабатывает только первый запрос с таким ключом. Это серверный подход, но фронтенд должен генерировать и передавать ключ.

Ключевая деталь для senior-уровня: блокировку нужно снимать в блоке finally, чтобы гарантировать разблокировку даже при ошибке сети или исключении в обработчике.

На практике

В реальных проектах комбинируют отключение кнопки с визуальной обратной связью (спиннер, изменение текста) и серверной идемпотентностью. Для критичных операций (оплата, создание заказа) обязательно добавляют проверку на сервере, так как фронтенд-защита не работает при повторной отправке запроса через инструменты разработчика или при сетевых задержках.

Важно также учитывать UX: кнопка должна быть отключена сразу после клика, а не после начала асинхронной операции, чтобы пользователь видел мгновенную реакцию.

Пример кода

JAVASCRIPT
const submitButton = document.getElementById('submit');
let isProcessing = false;
async function handleSubmit() {
if (isProcessing) return;
isProcessing = true;
submitButton.disabled = true;
submitButton.textContent = 'Отправка...';
try {
const response = await fetch('/api/order', {
method: 'POST',
body: JSON.stringify({ /* данные */ }),
headers: { 'Content-Type': 'application/json' }
});
// обработка успешного ответа
} catch (error) {
// обработка ошибки
} finally {
isProcessing = false;
submitButton.disabled = false;
submitButton.textContent = 'Заказать';
}
}
submitButton.addEventListener('click', handleSubmit);

Как отвечать на собеседовании

Начните с простого решения - отключение кнопки. Затем добавьте нюансы: использование finally, визуальную обратную связь, комбинацию с серверной защитой. Упомяните trade-off между UX и безопасностью - слишком долгая блокировка кнопки может раздражать пользователя. Покажите понимание, что фронтенд-защита не является абсолютной и должна дополняться серверными проверками.

Что проверяет интервьюер

Интервьюер оценивает понимание асинхронности в JavaScript, знание паттернов управления состоянием UI, умение предусмотреть edge cases (ошибки сети, повторные клики до завершения предыдущего запроса). Для senior-уровня важно показать системный подход: не только код, но и понимание UX, безопасности, взаимодействия с сервером.

Типичные ошибки

  • Снятие блокировки только в then без учёта ошибок - при сетевой ошибке кнопка остаётся заблокированной навсегда.
  • Использование setTimeout или debounce вместо явной блокировки - не гарантирует защиту при быстрых кликах.
  • Игнорирование визуальной обратной связи - пользователь не понимает, что действие обрабатывается.
  • Блокировка кнопки после асинхронной операции, а не до неё - создаёт race condition.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью