गेम लॉजिक के लिए Web Workers
Web Workers आपको JavaScript को एक background thread में चलाने देते हैं। गेम्स के लिए इसका मतलब है कि physics, AI और procedural generation बिना frames गिराए चल सकते हैं।
1) Workers का इस्तेमाल कब करें
अच्छे उम्मीदवार:
- Physics simulation
- Pathfinding (A*, navmesh)
- AI decision making
- Procedural generation
- Asset processing (image manipulation, compression)
- जटिल math (FFT, collision detection)
जिनके लिए सही नहीं:
- Rendering (Workers सीधे DOM/Canvas access नहीं कर सकते)
- बहुत छोटे tasks (thread का overhead इसके लायक नहीं होता)
2) एक बेसिक Worker बनाना
worker.js:
self.onmessage = (e) => {
const { type, data } = e.data
if (type === 'calculate') {
const result = heavyCalculation(data)
self.postMessage({ type: 'result', data: result })
}
}
function heavyCalculation(input) {
// Expensive work here
return input * 2
}main.js:
const worker = new Worker('worker.js')
worker.onmessage = (e) => {
const { type, data } = e.data
if (type === 'result') {
console.log('Got result:', data)
}
}
worker.postMessage({ type: 'calculate', data: 42 })3) Inline Workers (कोई अलग फाइल नहीं)
function createInlineWorker(fn) {
const blob = new Blob([`(${fn.toString()})()`], { type: 'text/javascript' })
return new Worker(URL.createObjectURL(blob))
}
const worker = createInlineWorker(() => {
self.onmessage = (e) => {
const result = e.data * 2
self.postMessage(result)
}
})4) ES module Workers
आप worker code को एक ES module की तरह लिख सकते हैं और उसके अंदर importScripts के बजाय import का इस्तेमाल कर सकते हैं। constructor को { type: 'module' } पास करें:
const worker = new Worker('physics-worker.js', { type: 'module' })worker के अंदर आप फिर शेयर्ड math, collision या AI helpers को उसी तरह import कर सकते हैं जैसे main thread पर करते हैं, ताकि गेम लॉजिक दोहराया न जाए। Module workers Chrome और Edge 80+, Safari 15+ और Firefox 114+ में सपोर्ट होते हैं।
5) Physics Worker का उदाहरण
physics-worker.js:
const bodies = []
const FIXED_DT = 1 / 60
self.onmessage = (e) => {
const { type, data } = e.data
switch (type) {
case 'init':
initWorld(data)
break
case 'step':
step()
break
case 'addBody':
bodies.push(data)
break
}
}
function initWorld(config) {
// Initialize physics world
}
function step() {
// Update physics
for (const body of bodies) {
body.vy += 9.8 * FIXED_DT // Gravity
body.x += body.vx * FIXED_DT
body.y += body.vy * FIXED_DT
}
// Send positions back
self.postMessage({
type: 'positions',
data: bodies.map(b => ({ id: b.id, x: b.x, y: b.y, rotation: b.rotation }))
})
}6) परफॉर्मेंस के लिए Transferable objects
बड़े data को बिना copy किए transfer किया जा सकता है:
// Main thread
const positions = new Float32Array(1000)
worker.postMessage(positions, [positions.buffer])
// positions is now unusable here (transferred)
// Worker
self.onmessage = (e) => {
const positions = e.data
// Work with positions
self.postMessage(positions, [positions.buffer])
}7) Pathfinding Worker
pathfinding-worker.js:
let grid = null
self.onmessage = (e) => {
const { type, data } = e.data
if (type === 'setGrid') {
grid = data
}
if (type === 'findPath') {
const path = aStar(data.start, data.end, grid)
self.postMessage({ type: 'path', id: data.id, path })
}
}
function aStar(start, end, grid) {
// A* implementation
const openSet = [start]
const cameFrom = new Map()
const gScore = new Map()
gScore.set(key(start), 0)
while (openSet.length > 0) {
// ... A* logic
}
return reconstructPath(cameFrom, end)
}
function key(pos) {
return `${pos.x},${pos.y}`
}8) Parallel tasks के लिए Worker pool
class WorkerPool {
constructor(workerUrl, size = navigator.hardwareConcurrency || 4) {
this.workers = []
this.queue = []
this.available = []
for (let i = 0; i < size; i++) {
const worker = new Worker(workerUrl)
worker.onmessage = (e) => this.handleResult(worker, e)
this.workers.push(worker)
this.available.push(worker)
}
}
run(data) {
return new Promise((resolve) => {
const task = { data, resolve }
if (this.available.length > 0) {
this.dispatch(this.available.pop(), task)
} else {
this.queue.push(task)
}
})
}
dispatch(worker, task) {
worker._currentTask = task
worker.postMessage(task.data)
}
handleResult(worker, e) {
const task = worker._currentTask
task.resolve(e.data)
if (this.queue.length > 0) {
this.dispatch(worker, this.queue.shift())
} else {
this.available.push(worker)
}
}
terminate() {
this.workers.forEach(w => w.terminate())
}
}9) रियल-टाइम sync के लिए SharedArrayBuffer
cross-origin isolation चालू होने पर, आप memory शेयर कर सकते हैं:
// Main thread
const shared = new SharedArrayBuffer(1024)
const positions = new Float32Array(shared)
worker.postMessage({ type: 'init', buffer: shared })
// Worker reads/writes directly to shared memory
// No postMessage overhead for position updates10) Workers के लिए OffscreenCanvas
एक Worker में render करें। OffscreenCanvas अब Chrome, Edge, Firefox और Safari में Baseline रूप से व्यापक रूप से उपलब्ध है (Safari ने macOS और iOS पर 17.0 में सपोर्ट जोड़ा):
// Main thread
const canvas = document.getElementById('game')
const offscreen = canvas.transferControlToOffscreen()
worker.postMessage({ canvas: offscreen }, [offscreen])
// Worker
self.onmessage = (e) => {
const canvas = e.data.canvas
const ctx = canvas.getContext('2d')
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
// Draw...
requestAnimationFrame(render)
}
render()
}11) Error handling
worker.onerror = (e) => {
console.error('Worker error:', e.message, e.filename, e.lineno)
}
// In worker
self.onerror = (e) => {
self.postMessage({ type: 'error', message: e.message })
}संबंधित
- तेज़ी से लोड होने वाला web game ship करें
- Wasm threads चालू करें (SharedArrayBuffer)
- Canvas 2D game loop
- Game physics libraries — Rapier या Cannon-es को एक Worker में चलाना
- Streaming asset loading — main thread से हटकर assets को decode करना
- 2026 में Web Games Tech Stack — Workers WebGL/WebGPU/Wasm stack में कैसे फिट होते हैं
बाहरी संसाधन
- MDN: Web Workers API — पूरा API reference
- MDN: Using Web Workers — step-by-step गाइड
- MDN: Transferable objects — zero-copy data transfer
- MDN: SharedArrayBuffer — threads के बीच shared memory