tgoop.com/frontend_punks/380
Last Update:
API браузера. Часть 1.
Многие из нас регулярно заходят в MDN что-бы подсмотреть что-то интересное, а на некоторых позициях часто в ежедневной верстке/типовых задачах забываешь, насколько много можно сделать с помощью браузера.
Этот пост пишу чтобы напомнить, и добавить живых примеров на описание API браузера в документации. В рамках одного поста сложно расписать все кейсы применения и интересных задач, которые могут быть связаны с каждым из API, поэтому ставил для себя задачу как минимум заинтересовать и, возможно подкинуть вдохновения на то что-бы попробовать что-то новое.
Пост вдохновлен официальной докой MDN
Сеть и данные
Fetch API + AbortController (таймауты/отмена) (очень распростаненное API)
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 8000); // 8s timeout
try {
const res = await fetch('/api/items', { signal: controller.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
} catch (e) {
console.error('Request failed:', e.name === 'AbortError' ? 'timeout' : e);
} finally {
clearTimeout(timeout);
}
Streams API (постепенная обработка ответа)
const res = await fetch('/api/logs/stream');
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log(decoder.decode(value, { stream: true }));
}
WebSocket (RT-обновления) (встречается очень часто) (также можно почитать про SSE, Socket.io)
const ws = new WebSocket('wss://example.com/ws');
ws.addEventListener('message', e => {
const msg = JSON.parse(e.data);
console.log('event:', msg);
});
ws.addEventListener('close', () => console.log('socket closed'));
BroadcastChannel (синхронизация между вкладками)
const ch = new BroadcastChannel('cart');
ch.onmessage = e => console.log('Cart updated in another tab:', e.data);
// где-то в другой вкладке:
new BroadcastChannel('cart').postMessage({ type: 'ADD', id: 123 });
Кэш, офлайн и PWA (pwa)
Service Worker регистрация + Cache Storage
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').catch(console.error);
}
// sw.js (минимум кэша статики)
self.addEventListener('install', e => {
e.waitUntil(caches.open('app-v1').then(c =>
c.addAll(['/','/styles.css','/app.js','/logo.png'])
));
});
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request))
);
});
IndexedDB - пригодится если работаете с большими табличными, например, данными
function openDB(name, version = 1) {
return new Promise((resolve, reject) => {
const req = indexedDB.open(name, version);
req.onupgradeneeded = () => req.result.createObjectStore('items', { keyPath: 'id' });
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
const db = await openDB('appdb');
const tx = db.transaction('items', 'readwrite');
tx.objectStore('items').put({ id: 1, title: 'Foo' });
await tx.complete?.(); // в некоторых браузерах не нужно
db.close();
Производительность и планирование (Web Workers часто спрашивают на собеседованиях)
Web Workers (не блокируем UI)
// worker.js
self.onmessage = ({ data }) => {
const result = heavyCompute(data);
self.postMessage(result);
};
// main
const worker = new Worker('/worker.js', { type: 'module' });
worker.postMessage({ n: 5e6 });
worker.onmessage = ({ data }) => console.log('Result:', data);
requestIdleCallback / Scheduler API (мягкая загрузка)
const schedule = cb =>
('scheduler' in window && scheduler.postTask)
? scheduler.postTask(cb, { priority: 'background' })
: (window.requestIdleCallback || setTimeout)(cb);
schedule(() => warmCachesOrPrecompute());