> Как реализовать бесконечную ленту (infinite scroll) в веб-приложении (JavaScript)

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

Компании: YADRO

Стек: JavaScript

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

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

Пример реализации на чистом JavaScript:

JAVASCRIPT
class InfiniteScroll {
constructor(container, fetchData) {
this.container = container;
this.fetchData = fetchData;
this.page = 1;
this.loading = false;
this.hasMore = true;
this.observer = null;
this.init();
}
init() {
// Создаем триггерный элемент
this.sentinel = document.createElement('div');
this.sentinel.className = 'scroll-sentinel';
this.container.appendChild(this.sentinel);
// Настраиваем IntersectionObserver
this.observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !this.loading && this.hasMore) {
this.loadMore();
}
}, { rootMargin: '200px' }); // Подгружаем за 200px до конца
this.observer.observe(this.sentinel);
}
async loadMore() {
this.loading = true;
this.showLoader();
try {
const data = await this.fetchData(this.page);
if (data.length === 0) {
this.hasMore = false;
this.observer.unobserve(this.sentinel);
} else {
this.renderItems(data);
this.page++;
}
} catch (error) {
console.error('Ошибка загрузки:', error);
// Можно показать кнопку "Повторить"
} finally {
this.hideLoader();
this.loading = false;
}
}
renderItems(items) {
items.forEach(item => {
const element = document.createElement('div');
element.className = 'item';
element.textContent = item.title;
this.container.insertBefore(element, this.sentinel);
});
}
showLoader() { /* Показываем спиннер */ }
hideLoader() { /* Прячем спиннер */ }
}
// Использование
const scroll = new InfiniteScroll(
document.getElementById('feed'),
(page) => fetch(`/api/items?page=${page}`).then(r => r.json())
);

Ключевые моменты:

  • IntersectionObserver эффективнее scroll-событий, так как не вызывает перерасчетов при каждом пикселе прокрутки
  • rootMargin позволяет начать загрузку заранее, чтобы контент успел подгрузиться до того, как пользователь дойдет до конца
  • Обязательно обрабатывать состояние загрузки (loading), чтобы избежать множественных запросов
  • При пустом ответе отключаем наблюдение, чтобы не делать лишних запросов
  • Для SEO и доступности стоит дублировать пагинацию в URL (например, через history.pushState) и добавлять aria-live-регионы

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

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