Перейти к содержимому

Другие полезные Web APIs

Современный браузер предоставляет десятки специализированных API; знание IntersectionObserver, ResizeObserver, MutationObserver и BroadcastChannel проверяется в вопросах о производительности — они заменяют дорогие паттерны вроде scroll-polling, setInterval-heartbeat и межвкладочного localStorage-хака.

// IntersectionObserver: lazy-load, infinite scroll, аналитика видимости
const io = new IntersectionObserver((entries) => {
for (const { target, isIntersecting } of entries) {
if (isIntersecting) {
target.src = target.dataset.src; // lazy load
io.unobserve(target); // отписка после загрузки
}
}
}, {
root: null, // viewport как root
rootMargin: '200px 0px', // preload за 200px до края
threshold: 0.1, // срабатывать при 10% видимости
});
document.querySelectorAll('img[data-src]').forEach(img => io.observe(img));
io.disconnect(); // отписать всех
// ResizeObserver: реакция на изменение размера элемента (не window)
const ro = new ResizeObserver(entries => {
for (const { target, contentRect, borderBoxSize } of entries) {
// contentRect: content-box; borderBoxSize[0].inlineSize — border-box ширина
target.style.fontSize = `${Math.max(12, contentRect.width / 20)}px`;
}
});
ro.observe(document.querySelector('.fluid-text'));
// MutationObserver: наблюдение за изменениями DOM
const mo = new MutationObserver(mutations => {
for (const m of mutations) {
if (m.type === 'childList') {
m.addedNodes.forEach(n => n.nodeType === 1 && console.log('added:', n.tagName));
m.removedNodes.forEach(n => console.log('removed:', n));
}
if (m.type === 'attributes') {
console.log(`${m.attributeName} changed on`, m.target, '', m.oldValue);
}
}
});
mo.observe(document.body, {
childList: true, // добавление/удаление дочерних
subtree: true, // всё поддерево (не только прямые дети)
attributes: true,
attributeFilter: ['class', 'data-state'],
attributeOldValue: true,
});
// mo.takeRecords() — синхронно получить накопленные мутации до срабатывания callback
mo.disconnect();
// Clipboard API (требует user gesture / разрешения)
await navigator.clipboard.writeText('copied to clipboard!');
const text = await navigator.clipboard.readText(); // требует permissions
// BroadcastChannel: pub/sub между вкладками без SharedWorker
const ch = new BroadcastChannel('app-events');
ch.postMessage({ type: 'THEME_CHANGED', value: 'dark' });
ch.addEventListener('message', e => {
if (e.data.type === 'LOGOUT') location.href = '/login';
});
ch.close(); // явное закрытие
// Screen Wake Lock: не гасить экран (видео-плееры, рецепты)
let lock;
async function keepScreenOn() {
lock = await navigator.wakeLock.request('screen');
}
document.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible' && lock?.released) {
lock = await navigator.wakeLock.request('screen');
}
});
// Web Notifications
const perm = await Notification.requestPermission();
if (perm === 'granted') {
new Notification('Сборка завершена', { body: 'Build succeeded in 4.2s', icon: '/icon.png' });
}
// navigator.onLine / offline event
window.addEventListener('offline', () => showBanner('No connection'));
window.addEventListener('online', () => hideBanner());

Итог: Observer API (Intersection, Resize, Mutation) работают асинхронно без блокировки main thread; BroadcastChannel — простейший pub/sub между вкладками без SharedWorker.