> Как реализовать показ попапа через 3 секунды после захода на сайт с возможностью закрытия и запоминанием закрытия между сессиями? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Tilda
Стек: JavaScript
> Пример ответа
Короткий ответ
Попап показываем через 3 секунды после загрузки страницы с помощью setTimeout. Для запоминания закрытия между сессиями используем localStorage - при закрытии попапа сохраняем флаг popupClosed: true с временной меткой. При повторном визите проверяем наличие флага и, если он есть и не истёк (например, 24 часа), не показываем попап. Закрытие реализуем через обработчик клика на кнопку или оверлей.
Подробное объяснение
Основная задача - показать попап с задержкой, не блокируя взаимодействие пользователя с сайтом, и запомнить факт закрытия на клиентской стороне. Ключевые моменты:
- Таймер:
setTimeoutс 3000 мс запускается после событияDOMContentLoadedилиload. Важно очищать таймер при закрытии попапа, чтобы избежать утечек памяти. - Хранение состояния:
localStorageподходит для простого флага, но нужно учитывать, что пользователь может очистить хранилище. Для более надёжного решения можно добавить временную метку и проверять актуальность (например, показывать попап раз в сутки). - Закрытие: обработчик на кнопку закрытия и/или клик вне попапа (overlay). После закрытия устанавливаем флаг в
localStorageи очищаем таймер. - Сброс при повторном визите: при загрузке страницы проверяем
localStorage. Если флаг есть и время не истекло - не показываем. Если истекло - удаляем флаг и показываем снова.
На практике
В реальном проекте стоит добавить:
- Анимацию появления (CSS transition или animation) для плавного UX.
- Обработку случая, когда пользователь быстро закрывает страницу до срабатывания таймера - таймер нужно очищать в
beforeunload. - Возможность показать попап только на определённых страницах (через URL-паттерн).
- Для A/B-тестов или персонализации - хранить не просто флаг, а объект с версией попапа и временем показа.
Пример кода
JAVASCRIPTconst POPUP_DELAY = 3000;const STORAGE_KEY = 'popup_closed';const EXPIRY_MS = 24 * 60 * 60 * 1000; // 24 часаfunction initPopup() {const popup = document.getElementById('popup');const closeBtn = document.getElementById('popup-close');let timerId = null;// Проверяем, не закрывал ли пользователь попап ранееconst stored = localStorage.getItem(STORAGE_KEY);if (stored) {const { timestamp } = JSON.parse(stored);if (Date.now() - timestamp < EXPIRY_MS) {return; // Не показываем}localStorage.removeItem(STORAGE_KEY);}function showPopup() {popup.classList.add('popup--visible');}function closePopup() {popup.classList.remove('popup--visible');localStorage.setItem(STORAGE_KEY, JSON.stringify({ timestamp: Date.now() }));if (timerId) {clearTimeout(timerId);timerId = null;}}// Запускаем таймер после загрузки DOMdocument.addEventListener('DOMContentLoaded', () => {timerId = setTimeout(showPopup, POPUP_DELAY);});// Закрытие по кнопкеcloseBtn.addEventListener('click', closePopup);// Закрытие по клику вне попапа (на overlay)popup.addEventListener('click', (e) => {if (e.target === popup) {closePopup();}});// Очищаем таймер при уходе со страницыwindow.addEventListener('beforeunload', () => {if (timerId) clearTimeout(timerId);});}initPopup();
Как отвечать на собеседовании
Начни с краткого описания подхода: setTimeout + localStorage. Затем углубись в детали: почему localStorage, а не sessionStorage (межсессионное хранение), как обрабатываешь edge cases (очистка таймера, истечение срока). Упомяни про анимации и доступность (aria-атрибуты для попапа). Если спросят про альтернативы - можно использовать IndexedDB для больших данных или куки с HttpOnly для серверного контроля, но для простого флага localStorage оптимален.
Что проверяет интервьюер
- Понимание асинхронности в браузере (event loop, таймеры).
- Умение работать с Web Storage API и учитывать его ограничения (синхронность, размер 5-10 МБ).
- Навыки обработки событий и управления состоянием UI.
- Внимание к UX: задержка, анимация, закрытие без блокировки.
- Знание best practices: очистка таймеров, проверка на существование элементов.
Типичные ошибки
- Использование
sessionStorageвместоlocalStorage- флаг сбрасывается при закрытии вкладки. - Отсутствие очистки таймера при закрытии попапа - попап может появиться после закрытия.
- Неучёт истечения срока хранения - пользователь никогда не увидит попап снова.
- Показ попапа до полной загрузки DOM - элементы могут отсутствовать.
- Игнорирование доступности: попап без focus trap или aria-атрибутов.
> Похожие задачи по frontend
Что еще можно сделать с помощью замыканий в JavaScript кроме счетчика
Что делает метод json() у объекта response в JavaScript
Почему страница зависает при обработке большого массива в JavaScript
Что делать чтобы не блокировать основной поток при обработке большого массива без использования web workers
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью