javascript
examples
examples.js⚡javascript
/**
* Web Workers - Examples
* Running JavaScript in background threads
*
* Note: These examples require a browser environment.
* Workers cannot be created from inline scripts.
*/
// =============================================================================
// 1. WORKER CREATION (INLINE EXAMPLE)
// =============================================================================
console.log('--- Web Worker Concepts ---');
// In a real browser environment, you would create a worker like this:
/*
const worker = new Worker('worker.js');
worker.postMessage({ type: 'start', data: [1, 2, 3, 4, 5] });
worker.onmessage = (event) => {
console.log('Received from worker:', event.data);
};
worker.onerror = (error) => {
console.error('Worker error:', error.message);
};
*/
// =============================================================================
// 2. SIMULATING WORKER BEHAVIOR
// =============================================================================
// For demonstration, we'll simulate worker behavior
class MockWorker {
constructor(workerFn) {
this.workerFn = workerFn;
this.onmessage = null;
this.onerror = null;
}
postMessage(data) {
// Simulate async worker processing
setTimeout(() => {
try {
const result = this.workerFn(data);
if (this.onmessage) {
this.onmessage({ data: result });
}
} catch (error) {
if (this.onerror) {
this.onerror(error);
}
}
}, 0);
}
terminate() {
this.onmessage = null;
this.onerror = null;
}
}
// =============================================================================
// 3. HEAVY COMPUTATION EXAMPLE
// =============================================================================
console.log('\n--- Heavy Computation ---');
// Worker function for prime number calculation
function primeWorkerFn(data) {
const { start, end } = data;
function isPrime(n) {
if (n < 2) return false;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) return false;
}
return true;
}
const primes = [];
for (let i = start; i <= end; i++) {
if (isPrime(i)) {
primes.push(i);
}
}
return { primes, count: primes.length };
}
const primeWorker = new MockWorker(primeWorkerFn);
primeWorker.onmessage = (event) => {
console.log(`Found ${event.data.count} primes`);
console.log('First 10:', event.data.primes.slice(0, 10));
};
primeWorker.postMessage({ start: 1, end: 1000 });
// =============================================================================
// 4. WORKER WITH PROMISE WRAPPER
// =============================================================================
console.log('\n--- Promise-Based Worker ---');
function createPromiseWorker(workerFn) {
return function (data) {
return new Promise((resolve, reject) => {
const worker = new MockWorker(workerFn);
worker.onmessage = (event) => {
resolve(event.data);
};
worker.onerror = (error) => {
reject(error);
};
worker.postMessage(data);
});
};
}
const asyncPrimes = createPromiseWorker(primeWorkerFn);
asyncPrimes({ start: 1, end: 500 })
.then((result) => console.log('Async result:', result.count, 'primes'))
.catch((error) => console.error('Error:', error));
// =============================================================================
// 5. WORKER POOL
// =============================================================================
console.log('\n--- Worker Pool ---');
class WorkerPool {
constructor(workerFn, size = 4) {
this.workers = [];
this.queue = [];
this.size = size;
this.workerFn = workerFn;
for (let i = 0; i < size; i++) {
this.workers.push({
worker: new MockWorker(workerFn),
busy: false,
});
}
}
execute(data) {
return new Promise((resolve, reject) => {
this.queue.push({ data, resolve, reject });
this.processQueue();
});
}
processQueue() {
const availableWorker = this.workers.find((w) => !w.busy);
if (!availableWorker || this.queue.length === 0) {
return;
}
const { data, resolve, reject } = this.queue.shift();
availableWorker.busy = true;
availableWorker.worker.onmessage = (event) => {
availableWorker.busy = false;
resolve(event.data);
this.processQueue();
};
availableWorker.worker.onerror = (error) => {
availableWorker.busy = false;
reject(error);
this.processQueue();
};
availableWorker.worker.postMessage(data);
}
terminate() {
this.workers.forEach((w) => w.worker.terminate());
this.workers = [];
}
}
// Using the pool
const pool = new WorkerPool(primeWorkerFn, 2);
async function runPoolExample() {
const ranges = [
{ start: 1, end: 250 },
{ start: 251, end: 500 },
{ start: 501, end: 750 },
{ start: 751, end: 1000 },
];
console.time('Pool execution');
const results = await Promise.all(ranges.map((range) => pool.execute(range)));
console.timeEnd('Pool execution');
const totalPrimes = results.reduce((sum, r) => sum + r.count, 0);
console.log('Total primes found:', totalPrimes);
}
setTimeout(runPoolExample, 100);
// =============================================================================
// 6. MESSAGE TYPES AND PROTOCOLS
// =============================================================================
console.log('\n--- Message Protocol ---');
// Worker with message types
function messageProtocolWorker(message) {
const { type, payload, id } = message;
switch (type) {
case 'CALCULATE':
return {
type: 'CALCULATE_RESULT',
id,
payload: payload.reduce((a, b) => a + b, 0),
};
case 'TRANSFORM':
return {
type: 'TRANSFORM_RESULT',
id,
payload: payload.map((x) => x * 2),
};
case 'FILTER':
return {
type: 'FILTER_RESULT',
id,
payload: payload.filter((x) => x > 5),
};
default:
return {
type: 'ERROR',
id,
error: `Unknown message type: ${type}`,
};
}
}
// Message handler with request/response tracking
class WorkerRPC {
constructor(workerFn) {
this.worker = new MockWorker(workerFn);
this.pending = new Map();
this.nextId = 0;
this.worker.onmessage = (event) => {
const { id, type, payload, error } = event.data;
if (this.pending.has(id)) {
const { resolve, reject } = this.pending.get(id);
this.pending.delete(id);
if (type === 'ERROR') {
reject(new Error(error));
} else {
resolve(payload);
}
}
};
}
call(type, payload) {
const id = this.nextId++;
return new Promise((resolve, reject) => {
this.pending.set(id, { resolve, reject });
this.worker.postMessage({ type, payload, id });
});
}
}
const rpc = new WorkerRPC(messageProtocolWorker);
setTimeout(async () => {
console.log('\n--- RPC Style Communication ---');
try {
const sum = await rpc.call('CALCULATE', [1, 2, 3, 4, 5]);
console.log('Sum:', sum);
const doubled = await rpc.call('TRANSFORM', [1, 2, 3, 4, 5]);
console.log('Doubled:', doubled);
const filtered = await rpc.call('FILTER', [1, 3, 5, 7, 9, 11]);
console.log('Filtered:', filtered);
} catch (error) {
console.error('RPC Error:', error);
}
}, 500);
// =============================================================================
// 7. TRANSFERABLE OBJECTS CONCEPT
// =============================================================================
console.log('\n--- Transferable Objects ---');
// Concept demonstration (actual transfer requires browser)
function demonstrateTransfer() {
// Creating a large buffer
const buffer = new ArrayBuffer(1024 * 1024); // 1MB
const view = new Uint8Array(buffer);
// Fill with data
for (let i = 0; i < view.length; i++) {
view[i] = i % 256;
}
console.log('Original buffer size:', buffer.byteLength);
// In a real worker:
// worker.postMessage(buffer, [buffer]);
// After transfer, buffer.byteLength would be 0
// Simulating transfer
const transferred = buffer.slice(0); // Copy in simulation
console.log('Transferred buffer size:', transferred.byteLength);
// In real transfer:
// console.log('Original after transfer:', buffer.byteLength); // 0
}
demonstrateTransfer();
// =============================================================================
// 8. SHARED ARRAY BUFFER CONCEPT
// =============================================================================
console.log('\n--- SharedArrayBuffer Concept ---');
// SharedArrayBuffer allows true shared memory
// Requires special headers: Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy
function demonstrateSharedMemory() {
// Creating shared memory
// const shared = new SharedArrayBuffer(1024);
// const array = new Int32Array(shared);
// Atomic operations for thread safety
// Atomics.add(array, 0, 1);
// Atomics.load(array, 0);
// Atomics.store(array, 0, 42);
// Atomics.compareExchange(array, 0, 42, 100);
console.log('SharedArrayBuffer allows multiple workers to share memory');
console.log('Use Atomics for thread-safe operations');
}
demonstrateSharedMemory();
// =============================================================================
// 9. INLINE WORKER CREATION
// =============================================================================
console.log('\n--- Inline Worker Pattern ---');
// Creating a worker from a function (browser pattern)
function createInlineWorker(fn) {
const blob = new Blob([`self.onmessage = ${fn.toString()}`], {
type: 'application/javascript',
});
// In browser: return new Worker(URL.createObjectURL(blob));
// For demonstration, return mock worker
return {
url: 'blob:worker-' + Date.now(),
terminate: () => {
// URL.revokeObjectURL(url);
},
};
}
const inlineWorkerInfo = createInlineWorker(function (event) {
const result = event.data.map((x) => x * x);
self.postMessage(result);
});
console.log('Inline worker created:', inlineWorkerInfo.url);
// =============================================================================
// 10. PROGRESSIVE COMPUTATION
// =============================================================================
console.log('\n--- Progressive Computation ---');
function progressiveWorker(data) {
const { items, chunkSize } = data;
const results = [];
const progress = [];
for (let i = 0; i < items.length; i += chunkSize) {
const chunk = items.slice(i, i + chunkSize);
const processed = chunk.map((x) => x * x);
results.push(...processed);
progress.push({
processed: Math.min(i + chunkSize, items.length),
total: items.length,
percent: Math.round(((i + chunkSize) / items.length) * 100),
});
}
return { results, progress };
}
// Simulating progressive updates
async function runProgressiveExample() {
console.log('\n--- Running Progressive Example ---');
const items = Array.from({ length: 100 }, (_, i) => i);
const worker = new MockWorker(progressiveWorker);
worker.onmessage = (event) => {
const { results, progress } = event.data;
console.log('Final results count:', results.length);
console.log('Progress steps:', progress.length);
console.log('Last progress:', progress[progress.length - 1]);
};
worker.postMessage({ items, chunkSize: 25 });
}
setTimeout(runProgressiveExample, 800);
// =============================================================================
// 11. ERROR HANDLING IN WORKERS
// =============================================================================
console.log('\n--- Worker Error Handling ---');
function errorProneWorker(data) {
if (data.shouldFail) {
throw new Error('Intentional worker error');
}
return { success: true, data: data.value * 2 };
}
function createResilientWorker(workerFn) {
return {
execute(data) {
return new Promise((resolve, reject) => {
const worker = new MockWorker(workerFn);
const timeout = setTimeout(() => {
worker.terminate();
reject(new Error('Worker timeout'));
}, 5000);
worker.onmessage = (event) => {
clearTimeout(timeout);
resolve(event.data);
};
worker.onerror = (error) => {
clearTimeout(timeout);
reject(error);
};
worker.postMessage(data);
});
},
};
}
const resilientWorker = createResilientWorker(errorProneWorker);
setTimeout(async () => {
console.log('\n--- Resilient Worker Demo ---');
try {
const result1 = await resilientWorker.execute({ value: 21 });
console.log('Success result:', result1);
} catch (error) {
console.log('Error:', error.message);
}
try {
const result2 = await resilientWorker.execute({ shouldFail: true });
console.log('This should not print:', result2);
} catch (error) {
console.log('Caught error:', error.message);
}
}, 1000);
console.log('\n=== Examples loaded. Check output above and below. ===');