Неверная статистика пользователя в каталоге пользователей

В итоге это оказалась неприятная «гонка условий» между «сигнальным элементом» (sentinel), который мы используем для определения момента, когда нужно выполнить действие «загрузить ещё», и отрисовкой строк в каталоге пользователей :exploding_head:

Проблема

При наличии не менее 50 пользователей страница /u (каталог пользователей) сразу при первой загрузке вызывала loadMore, ещё до того, как пользователь успевал прокрутить страницу вниз. Это приводило к автоматической загрузке нежелательной второй страницы результатов.

Коренная причина

Гонка условий по времени при первоначальной загрузке страницы:

  1. Пользователь переходит на /u
  2. controllers/users начинает загрузку данных (isLoading: true)
  3. Шаблон отрисовывается с ConditionalLoadingSpinner, показывающим индикатор загрузки
  4. Данные загружаются, isLoading становится false
  5. Индикатор загрузки скрывается, DirectoryTable начинает отрисовку 50 пользователей
  6. В DOM вставляется сигнальный элемент LoadMore
  7. Создаётся IntersectionObserver и сразу начинает отслеживание
  8. В этот момент таблица всё ещё вычисляет макет и расширяется до полной высоты
  9. Сигнальный элемент на короткое время оказывается в области видимости (~292 пикселя от верха) до того, как таблица расширится
  10. Наблюдатель обнаруживает пересечение → запускает loadMore :cross_mark:
  11. Таблица завершает расширение до полной высоты (~3689 пикселей)
  12. Сигнальный элемент перемещается в правильное положение (~3959 пикселей, ниже области видимости)

Наблюдатель был «слишком нетерпелив» — он начал отслеживание до завершения разметки контента, зафиксировав сигнальный элемент в тот краткий момент, когда таблица ещё не достигла своей конечной высоты.

Исправление

Задержка создания наблюдателя до готовности контента:

Добавлен параметр @isLoading в LoadMore, который предотвращает создание IntersectionObserver, пока контент ещё загружается.

Как это работает теперь

Загрузка страницы → isLoading=true → Модификатор пропускает создание наблюдателя
             ↓
Загрузка данных → isLoading=false → Модификатор перезапускается, создаёт наблюдатель
             ↓
Таблица полностью расширена → Сигнальный элемент в правильном положении (ниже области видимости)
             ↓
Пользователь прокручивает вниз → Сигнальный элемент попадает в область видимости → loadMore срабатывает ✓

5 лайков