Карта с офисом — на странице контактов. Логично ожидать, что API карт грузится там же. На одном сайте мы нашли API Яндекс Карт на каждой странице с формой — то есть почти на всех. 465 КБ скриптов и 350 мс блокировки главного потока у каждого посетителя, хотя сама карта была только на странице контактов.

Это тридцать третья часть цикла «PageSpeed без мифов».

Как карты оказались везде

API карт подключался в сборке как «внешний модуль» — так удобно писать import ymaps from "ymaps" в коде. Казалось, что он загрузится только при import() там, где нужна карта. На деле внешний модуль типа script загружается, когда выполняется файл сборки, в котором он объявлен, — а этот файл грузился на всех страницах с формой. Мест, откуда в сборку попадали карты, по коду нашлось шесть.

Проверка: откройте страницу без карты, вкладка Network, фильтр по «maps». Если API грузится там, где карты нет, — та же история.

Лечение: свой загрузчик

Вместо внешнего модуля сборки — маленький загрузчик, который вставляет скрипт API, когда его действительно попросили, и отдаёт один и тот же промис всем, кто попросит повторно:

// ymaps.js — API карт загружается один раз и только по запросу
let api = null;

export function loadMaps() {
  if (api) return api;
  api = new Promise((resolve, reject) => {
    const s = document.createElement("script");
    s.src = "https://api-maps.yandex.ru/2.1/?apikey=КЛЮЧ&lang=ru_RU";
    s.async = true;
    s.onload = () => window.ymaps.ready(() => resolve(window.ymaps));
    s.onerror = reject;
    document.head.append(s);
  });
  return api;
}

// карта на странице: грузим, когда блок рядом с экраном, и не раньше, чем страница загрузилась
const box = document.querySelector("[data-map]");
if (box) {
  const io = new IntersectionObserver(([e]) => {
    if (!e.isIntersecting) return;
    io.disconnect();
    const go = () => loadMaps().then(ymaps => drawMap(ymaps, box));
    document.readyState === "complete" ? go() : addEventListener("load", () => setTimeout(go, 1500), { once: true });
  }, { rootMargin: "200px 0px" });
  io.observe(box);
}
  • Один промис — сколько бы компонентов ни запросили карты, скрипт загрузится один раз.
  • По приближению к экрану — карта внизу страницы не грузится, пока до неё не долистали.
  • Не раньше полной загрузки страницы и с запасом в полторы секунды — тяжёлый чужой скрипт не попадёт в окно первой отрисовки, даже если блок карты близко.

Отдельная ловушка: большой запас наблюдателя

Компоненты с большим rootMargin (например, 300 px у карты или 100% у видео) на телефоне оказываются «почти на первом экране»: наблюдатель срабатывает сразу после отрисовки, и тяжёлый сторонний код едет вместе с первым экраном. Для тяжёлого чужого кода берите небольшой запас и добавляйте условие «после load», как в примере.

Ещё дешевле: картинка вместо карты

Если карта нужна только чтобы показать, где офис, можно вообще не грузить API: показать статичную картинку карты (Static API у Яндекса и Google) со ссылкой «открыть в Картах». Интерактивную карту — по клику. Это ноль скриптов до действия посетителя.

Карты, чаты и виджеты грузятся там, где не нужны?

Пришлите адрес — найду лишние подключения и сколько они стоят.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.