JavaScript Browser Web APIs Explained — Geolocation, Notifications, Workers & Observers
Browser Web APIs extend JavaScript beyond basic syntax, giving you access to device features, background processing, and browser internals. The Doda Browser uses Web Workers for tab isolation and the Notification API for download alerts. The Durga Antivirus Pro dashboard uses Intersection Observer to lazy-load scan results and Web Workers for background threat analysis.
What You’ll Learn
- Geolocation API — getting the user’s location
- Notification API — sending system notifications
- Web Workers — running code in background threads
- Service Workers — intercepting network requests
- Intersection Observer — detecting element visibility
- Resize Observer — responding to element size changes
- Clipboard API — reading and writing clipboard data
- Building a custom notification system
Why Web APIs Matter
Web APIs turn JavaScript from a simple page-scripting language into a platform for building full-featured applications. Without the Geolocation API, Google Maps couldn’t show your location. Without Web Workers, complex spreadsheet apps would freeze during calculations. These APIs bridge the gap between web apps and native apps.
Learning Path
flowchart LR
A[JS DOM & Browser APIs] --> B[Browser Storage]
B --> C[Web APIs]
C --> D[Performance]
C --> E[You Are Here]
Geolocation API
Get the user’s current position (requires permission):
function getCurrentPosition() {
return new Promise((resolve, reject) => {
if (!navigator.geolocation) {
reject(new Error('Geolocation not supported'));
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy
});
},
(error) => {
switch (error.code) {
case error.PERMISSION_DENIED:
reject(new Error('User denied location access'));
break;
case error.POSITION_UNAVAILABLE:
reject(new Error('Location unavailable'));
break;
case error.TIMEOUT:
reject(new Error('Location request timed out'));
break;
}
},
{ enableHighAccuracy: true, timeout: 5000, maximumAge: 30000 }
);
});
}
// Usage
try {
const pos = await getCurrentPosition();
console.log(`Latitude: ${pos.lat}, Longitude: ${pos.lng}`);
} catch (error) {
console.error('Location error:', error.message);
}Security note: Geolocation requires HTTPS (except on localhost) and prompts the user for permission. Respect the user’s choice — don’t request location unless your feature genuinely needs it.
Notification API
Send system notifications outside the browser window:
async function showNotification(title, body) {
// Request permission
const permission = await Notification.requestPermission();
if (permission !== 'granted') {
throw new Error('Notification permission denied');
}
// Show notification
const notification = new Notification(title, {
body: body,
icon: '/icon-192.png',
tag: 'unique-tag', // Replaces existing notifications with same tag
vibrate: [200, 100, 200]
});
// Handle click
notification.onclick = () => {
window.focus();
notification.close();
};
// Auto-close after 10 seconds
setTimeout(() => notification.close(), 10000);
}
await showNotification('Scan Complete', 'No threats found in 1,247 files');Web Workers
Run CPU-intensive code in a separate thread without blocking the UI:
// main.js
const worker = new Worker('scanner-worker.js');
worker.postMessage({
cmd: 'scan',
files: ['file1.pdf', 'file2.exe', 'file3.jpg']
});
worker.onmessage = (event) => {
console.log('Scan result:', event.data);
// Output: Scan result: { threats: 0, scanned: 3 }
};
worker.onerror = (error) => {
console.error('Worker error:', error.message);
};
// scanner-worker.js
self.onmessage = (event) => {
const { cmd, files } = event.data;
if (cmd === 'scan') {
// Simulate heavy scanning
const results = files.map(file => ({
file,
threats: Math.floor(Math.random() * 2),
timestamp: Date.now()
}));
self.postMessage({ threats: results.filter(r => r.threats > 0).length, scanned: files.length });
}
};Real-world use: The Durga Antivirus Pro web dashboard uses a Web Worker to scan file signatures in the background. The main thread stays responsive so users can browse the UI while scanning runs.
Worker Lifecycle
- Create:
new Worker('script.js') - Communicate:
postMessage()/onmessage - Terminate:
worker.terminate()(from main) orself.close()(from worker) - Errors:
worker.onerrorcatches uncaught errors in the worker
Service Workers
Service Workers act as a programmable network proxy, enabling offline support, caching, and push notifications:
// Register service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg.scope))
.catch(err => console.error('SW failed:', err));
}
// sw.js — basic offline cache
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('app-v1').then(cache => {
return cache.addAll([
'/',
'/styles/main.css',
'/scripts/app.js'
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(cached => cached || fetch(event.request))
);
});Service Workers only work over HTTPS (or localhost). They’re the foundation of Progressive Web Apps (PWAs).
Intersection Observer
Detect when elements enter or leave the viewport — perfect for lazy loading and infinite scroll:
function observeVisibility(element, callback) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
callback(entry.target);
observer.unobserve(entry.target); // Only fire once
}
});
}, {
threshold: 0.1, // 10% visible
rootMargin: '50px' // Trigger 50px early
});
observer.observe(element);
return () => observer.disconnect();
}
// Lazy load images
document.querySelectorAll('img[data-src]').forEach(img => {
observeVisibility(img, (el) => {
el.src = el.dataset.src;
el.removeAttribute('data-src');
});
});Resize Observer
Respond to element size changes (not just window resize):
const box = document.getElementById('responsive-box');
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
console.log(`Box is now ${width}x${height}`);
// Adjust layout based on size
if (width < 300) {
box.classList.add('compact');
} else {
box.classList.remove('compact');
}
}
});
observer.observe(box);Difference from window resize: ResizeObserver watches individual elements, not just the viewport. Use it for responsive components inside a dashboard or editor.
Clipboard API
Read and write clipboard contents securely:
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Copied:', text);
} catch (err) {
console.error('Copy failed:', err);
}
}
async function readFromClipboard() {
try {
const text = await navigator.clipboard.readText();
return text;
} catch (err) {
console.error('Read failed:', err);
return '';
}
}
// Copy on click
document.getElementById('copyBtn').addEventListener('click', () => {
copyToClipboard('Hello from Doda Browser!');
});Custom Notification System
Combine the Notification API with a Web Worker for persistent alerts:
// notification-manager.js
class NotificationManager {
constructor(workerScript = 'notification-worker.js') {
this.worker = new Worker(workerScript);
this.handlers = new Map();
this.worker.onmessage = (event) => {
const { type, data } = event.data;
const handler = this.handlers.get(type);
if (handler) handler(data);
};
}
requestPermission() {
return Notification.requestPermission();
}
schedule(title, body, delay) {
this.worker.postMessage({
cmd: 'schedule',
payload: { title, body, delay }
});
}
on(type, handler) {
this.handlers.set(type, handler);
}
}
// notification-worker.js
self.onmessage = (event) => {
const { cmd, payload } = event.data;
if (cmd === 'schedule') {
setTimeout(() => {
self.postMessage({
type: 'notification',
data: {
title: payload.title,
body: payload.body,
timestamp: Date.now()
}
});
}, payload.delay);
}
};Common Mistakes
1. Using Web APIs without checking support
navigator.geolocation.getCurrentPosition(...) // Crashes if unsupported
Fix: Always check for the API first: if ('geolocation' in navigator).
2. Creating too many Web Workers
Each worker is a separate OS thread. Create workers sparingly and reuse them.
3. Not handling permission denial
const notif = new Notification('Hi'); // Throws if permission denied
Fix: Always check permission or use Notification.requestPermission() first.
4. Service Worker scope confusion
A Service Worker in /scripts/sw.js can only control pages in /scripts/. Fix: Place the worker file at the root level for maximum scope.
5. Not disconnecting observers
const observer = new IntersectionObserver(...);
observer.observe(element);
// Never disconnect — memory leak!
Fix: Call observer.disconnect() when the component is destroyed.
Practice Questions
What’s the difference between Web Workers and Service Workers? Web Workers are for CPU-intensive background tasks. Service Workers act as network proxies for offline support and push notifications.
When would you use Intersection Observer instead of scroll events? Intersection Observer is more performant (runs off the main thread) and easier to use for visibility detection.
Why do some Web APIs require HTTPS? For security — APIs like Geolocation, Notifications, and Service Workers can be abused on insecure connections.
What happens when a Web Worker throws an uncaught error? The
worker.onerrorevent fires in the main thread. The worker stops unless you handle the error.
Challenge: Build a lazy image loader using Intersection Observer that also handles responsive images (srcset).
Mini Project: Background File Scanner
// file-scanner.js
class FileScanner {
constructor() {
this.worker = new Worker('scan-worker.js');
this.results = new Map();
}
scan(file) {
return new Promise((resolve, reject) => {
const id = crypto.randomUUID();
this.results.set(id, { resolve, reject });
this.worker.postMessage({ id, file });
this.worker.onmessage = (e) => {
const handler = this.results.get(e.data.id);
if (handler) {
handler.resolve(e.data.result);
this.results.delete(e.data.id);
}
};
this.worker.onerror = (e) => {
const handler = this.results.get(id);
if (handler) {
handler.reject(e);
this.results.delete(id);
}
};
});
}
}
// Usage
const scanner = new FileScanner();
const result = await scanner.scan(largeFile);
console.log('Scan result:', result);FAQ
What’s Next
| Lesson | Description |
|---|---|
| JavaScript Home | Back to the JavaScript hub |
| https://tutorials.dodatech.com/programming-languages/javascript/js-dom/ | DOM & Browser APIs |
| https://tutorials.dodatech.com/programming-languages/javascript/js-storage/ | Browser Storage |
| https://tutorials.dodatech.com/programming-languages/javascript/js-performance/ | JavaScript performance optimization |
| PWA | Progressive Web Apps |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
What’s Next
Congratulations on completing this JavaScript Web APIs tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro