Привет! У меня на сайте основная страница имеет много JS кода. Для оптимизации загрузки я сделал загрузку скриптов интерактивной географической карты через Intersection Observer:
const sectionMap = document.querySelector(".js-section-map");
const observerOptions = { rootMargin: '100px' };
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/assets/js/map/sw.bundle.js')
.then(reg => {
console.log('Service Worker для карты зарегистрирован', reg);
})
.catch(err => {
console.warn('Ошибка регистрации Service Worker для карты:', err);
});
}
if (sectionMap) {
const observer = new IntersectionObserver(onIntersection, observerOptions);
observer.observe(sectionMap);
function onIntersection(entries, observer) {
entries.forEach(async (entry) => {
if (entry.isIntersecting) {
try {
await import(/* webpackChunkName: "map" */ './map.mjs');
await import(/* webpackChunkName: "modalMap" */ './modalMap.mjs');
} catch (error) {
console.error('Ошибка загрузки карты:', error);
}
observer.unobserve(entry.target);
}
})
}
}
Логика такая: когда пользователь докрутит до блока с картой, срабатывает IO и загружает нужные скрипты - в коде динамический импорт. Однако ниже блока с картой находится много блочков с кнопкой вызова модалки, в которую вставляется эта карта. Кнопки активируются тоже после срабатывания IO (modalMap.mjs). Всё работает. Но! Если пользователь перезагружает страницу, он остаётся на том уровне страницы, где случилась перезагрузка. И если карту не пересекали, карта и кнопки вызова модалки не работают. Нужно снова крутить вверх до карты, чтобы IO опять загрузил скрипты, заработала карта и кнопки, а затем крутить вниз до места, где остановились. Ужасно неудобно.
Пришла идея использовать Service Worker (сайт - аудиогид, в основном для мобильных устройств, поэтому захотелось сделать работу карты также в офлайн режиме). Написал такой код:
const CACHE_NAME = 'map-scripts-cache-v1';
const MAP_SCRIPTS_PATH = '/assets/js/map/'; // путь от корня сайта
self.addEventListener('install', (event) => {
// При установке SW сразу кэшируем все нужные файлы из папки map.
// Чтобы минимизировать, список можно держать статичным или сгенерировать при билде.
const urlsToCache = [
`${MAP_SCRIPTS_PATH}mapLazy.bundle.js`,
`${MAP_SCRIPTS_PATH}map.bundle.js`,
`${MAP_SCRIPTS_PATH}modalMap.bundle.js`,
`${MAP_SCRIPTS_PATH}leaflet.bundle.js`,
];
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
.then(() => self.skipWaiting())
);
});
self.addEventListener('activate', (event) => {
// Удаляем старые кеши при обновлении SW
event.waitUntil(
caches.keys()
.then(keys => Promise.all(
keys.filter(key => key !== CACHE_NAME).map(key => caches.delete(key))
))
.then(() => self.clients.claim())
);
});
self.addEventListener('fetch', (event) => {
// Перехватываем запросы к нашим скриптам из папки map
if (event.request.url.includes(MAP_SCRIPTS_PATH)) {
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
if (cachedResponse) {
return cachedResponse;
}
// Если в кеше нет — запросим из сети и добавим в кеш
return fetch(event.request).then(networkResponse => {
return caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
});
})
);
}
});
Всё работает, но! Тогда скрипты - в т.ч. которые были отложены для IO - грузятся в кэш сразу. Я не до конца понимаю ещё Service Worker и возникают вопросы:
- Раз скрипты выкачиваются сразу, то исчезает смысл в IO. Но, тогда, получается, убивается идея ускорить загрузку страницу при первичном заходе на неё!
- Попробовали с ИИ переписать код, чтобы SW перехватывал запрос в момент срабатывания IO, забирал скрипты и записывал их в кэш. Но он НЕ записывает ничего в кэш в такой ситуации. Получается, что fetch SW срабатывает только в самом начале загрузки страницы и никак с IO не общается?
- Я прочитал, что, вроде, SW это вообще отдельный поток и он non-blocking. Получается, тогда идея IO вообще лишена смысла?
- Если IO в таком случае не нужен, как переписать IO, чтобы он всегда грузил скрипты только из кэша?
Помогите, пожалуйста, кто разбирается в этой технологии. Ещё раз очерчу цель:
- Максимально ускорить загрузку странице при первичном заходе на сайт (карта не в первом экране) на мобильных
- Иметь сразу загруженные скрипты, если карту пересекали, но перезагрузили страницу - чтобы сразу были активны кнопки вызова модалки.