Browser & DOM APIs
DOM manipulation, browser APIs, and web storage
Browser and DOM APIs are the runtime environment that JavaScript executes in. Understanding how the browser event loop, Web APIs, and DOM manipulation work is essential for building performant UIs and for passing frontend technical interviews.
The Event Loop
JavaScript is single-threaded. The event loop continuously checks the call stack and — when it is empty — moves callbacks from the task queue (macrotasks) or microtask queue (Promises) onto the stack for execution.
console.log('1'); // synchronous
setTimeout(() => console.log('4'), 0); // macrotask
Promise.resolve()
.then(() => console.log('3')); // microtask — runs before macrotasks
console.log('2'); // synchronous
// Output: 1, 2, 3, 4
// Microtasks (Promises) drain before the next macrotask
DOM Querying and Manipulation
// Modern selectors
const btn = document.querySelector('#submit');
const items = document.querySelectorAll('.item');
// Create and append elements
const li = document.createElement('li');
li.textContent = 'New item';
li.classList.add('item', 'item--new');
document.querySelector('ul').append(li);
// Efficient bulk DOM update — use DocumentFragment to avoid multiple reflows
const frag = document.createDocumentFragment();
data.forEach(item => {
const li = document.createElement('li');
li.textContent = item.name;
frag.appendChild(li);
});
document.querySelector('ul').appendChild(frag);
Event Delegation
Attach one listener to a parent instead of individual listeners on each child. More efficient for dynamic lists and large numbers of elements.
// Instead of adding listeners to every button:
document.querySelector('.list').addEventListener('click', (e) => {
const btn = e.target.closest('[data-action]');
if (!btn) return;
const action = btn.dataset.action;
const id = btn.closest('[data-id]').dataset.id;
handle(action, id);
});
Intersection Observer — Lazy Loading
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
}, { rootMargin: '200px', threshold: 0 });
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
Web Storage APIs
// localStorage — persists across sessions, ~5MB, same-origin only
localStorage.setItem('user', JSON.stringify({ id: 1, name: 'Alice' }));
const user = JSON.parse(localStorage.getItem('user'));
localStorage.removeItem('user');
// sessionStorage — cleared when tab closes
sessionStorage.setItem('draft', JSON.stringify(formData));
// Cookies — sent with every HTTP request, configurable expiry, accessible server-side
document.cookie = 'theme=dark; max-age=31536000; path=/; SameSite=Lax; Secure';
Fetch and AbortController
// Cancellable fetch — important for React useEffect cleanup
function fetchUser(id) {
const controller = new AbortController();
const promise = fetch('/api/users/' + id, { signal: controller.signal })
.then(res => { if (!res.ok) throw new Error(res.status); return res.json(); });
return { promise, cancel: () => controller.abort() };
}
// In React:
useEffect(() => {
const { promise, cancel } = fetchUser(id);
promise.then(setUser).catch(err => { if (err.name !== 'AbortError') setError(err); });
return cancel; // cleanup on unmount or id change
}, [id]);
Key Interview Topics to Know
- Event bubbling vs capturing;
stopPropagationvspreventDefault - How
requestAnimationFramediffers fromsetTimeout - Difference between
localStorage,sessionStorage, and cookies - Same-origin policy and CORS
- Virtual DOM vs real DOM — why React uses a VDOM