tl;dr: используйте внутренний onResourceLoad API

NProgress — очаровательная маленькая библиотека, которая легко создает плавно анимированную полосу загрузки вверху страницы. Многие сайты используют его, чтобы убедить пользователя в том, что загрузка процессов, например сетевых запросов или IO, займет небольшое количество времени.

Мы все видели логику, похожую на следующую (как на Medium и GitHub!):

Прелесть функции .inc() в том, что она никогда не доводит полосу до конца. Это как Ахиллес и черепаха, за исключением того, что вместо изучения математической красоты бесконечности ваши пользователи готовы ждать завершения.

Одним из недостатков подхода с использованием таймера является то, что он предполагает, что задача завершается в относительно предсказуемое время. Это предположение может развалиться для сетевых запросов, если у пользователя медленное соединение. Они увидят, как полоса прогресса постоянно сползает вправо, пока их компьютер продолжает загружаться… и загружаться… и в конце концов пользователь вообще теряет веру в полоски загрузки. Печальный день.

Если вы действительно хотите получить точную оценку загрузки, есть несколько вариантов:

  • Рассчитайте предполагаемую скорость соединения пользователя на основе среднего значения каждого запроса (размер данных / затраченное время)
  • Какая-то причудливая система перекачки данных на основе сокетов, где клиентский код управляет событиями для потоков данных.
  • В задачах с большим количеством сетевых запросов увеличивайте индикатор выполнения после завершения каждого сетевого запроса.

Первые два тяжелые. Поговорим о третьем.

RequireJS имеет открытый внутренний API под названием onResourceLoad, который запускается всякий раз, когда загружается ресурс.

«Внутренний» означает, что он может быть изменен в любое время. Пожалуйста, немного беспокойтесь о том, что этот метод в конечном итоге изменится или станет устаревшим. Это очень рискованно.

Вместо того, чтобы .inc() работать с интервалом, мы можем .inc() работать с загрузкой ресурсов.

Проблема: что произойдет, если у вас много запросов?

Что ж, NProgress.inc() не может знать, сколько запросов у вас есть в целом. Когда запущено всего несколько из них, полоса загрузки кажется разумной, но когда вы добираетесь до десятков, она начинает зависать ближе к концу. Для такого масштаба требуется более интеллектуальный индикатор выполнения.

Есть снова куча способов, которыми вы могли бы это сделать. Оптимизируя здесь время загрузки страницы с большим количеством сценариев, нам нужен способ сравнить, сколько сценариев мы завершили и сколько запустили.

RequireJS хранит объект context для вашего текущего пользовательского сеанса, который содержит статус для каждого загружаемого ресурса. Это первый аргумент, переданный onResourceLoad. Все, что нам действительно нужно, — это количество имен (запущенных запросов).

Я начал использовать их варианты для начальных загрузок страниц на страницах, где не все зависимости объединены в один скрипт. Это не точные измерения, но они лучше отражают общий прогресс.