Реалізація Web Workers для фонових обчислень на сайті

Реалізація Web Workers для фонових обчислень на сайті

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Реалізація Web Workers для фонових обчислень на сайті
Середній
~2-3 дні

Наші компетенції:

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1422
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1288
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    984
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1250
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    988
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    1001

Реалізація Web Workers для фонових обчислень на сайті

Уявіть: користувач завантажує CSV-файл на 10 МБ, і інтерфейс зависає на 5 секунд. Скрол не реагує, кнопки не натискаються. Це відбувається, тому що JavaScript — однопотоковий, і парсинг блокує UI. Рішення — вивантаження важких обчислень у Web Workers. Наш досвід: 10+ років у високонавантажених веб-додатках, 50+ проєктів з Workers, прискорення взаємодії у 3–5 разів. Звертайтеся — ми впровадимо багатопотоковість під ваш стек і терміни.

Web Workers не мають доступу до DOM, window, document. Спілкування з main thread — тільки через повідомлення (postMessage/onmessage). Це обмеження — захист від race conditions. Ми використовуємо типізовані обгортки та Transferable Objects для ефективної передачі великих даних. Детальніше про API — у документації MDN.

Які задачі вирішують Web Workers?

  • Парсинг і трансформація великих CSV/JSON (>1 MB) — прискорення в 4 рази за рахунок вивантаження з основного потоку.
  • Шифрування/дешифрування даних (AES, RSA) — займає 500 ms у main thread, у Worker — без впливу на UI.
  • Рендеринг Canvas-графіки через OffscreenCanvas — усе малювання в фоні, основний потік тільки реагує на введення користувача.
  • Алгоритми пошуку та сортування на великих масивах (10⁶+ елементів) — з пулом Worker-ів паралельно за секунди.
  • Компресія даних (pako, zlib) — стиснення перед відправкою на сервер без блокування інтерфейсу.
  • Фізичні симуляції та ray tracing — для інтерактивних візуалізацій.

Як впровадити Web Workers без втрати продуктивності?

Ключові принципи:

  • Transferable Objects — передача ArrayBuffer, ImageBitmap, OffscreenCanvas за посиланням (без копіювання) для великих даних.
  • Пул Worker-ів — за кількістю ядер CPU, розподіл задач через єдину чергу.
  • Типізовані обгортки — виключення помилок типів при обміні повідомленнями.
  • Обробка помилок на рівні планувальника — перезапуск впалого Worker-а без втрати даних.
Метод передачі даних Швидкість Підтримка Застосування
Structured clone 1x (копіювання) Всі браузери Дрібні дані (<1MB)
Transferable Objects 10x+ (без копіювання) Chrome, Firefox, Safari 16.4+ ArrayBuffer, ImageBitmap
Детальніше про Transferable Objects Передача об'єктів за посиланням можлива для ArrayBuffer, ImageBitmap, OffscreenCanvas, ReadableStream, WritableStream. Після виклику postMessage з масивом transferables вихідний об'єкт стає недоступним у відправнику, що виключає гонки даних. Це критично для буферів від 10 MB — затримка знижується в десятки разів.

Базова структура Worker

// worker.ts — фоновий потік self.onmessage = ({ data }: MessageEvent) => { const result = heavyComputation(data.payload); self.postMessage({ type: 'RESULT', payload: result }); }; // main.ts — основний потік const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' }); worker.postMessage({ type: 'PROCESS', payload: largeArray }); worker.onmessage = (event) => console.log('Результат:', event.data.payload); worker.onerror = (error) => console.error('Worker error:', error.message); worker.terminate(); 

Типізована обгортка

Працювати з сирим postMessage незручно. Типізована обгортка вирішує це:

type WorkerMessage<T extends Record<string, unknown>> = { [K in keyof T]: { type: K; payload: T[K] } }[keyof T]; interface WorkerRequest { SORT: { array: number[]; direction: 'asc' | 'desc' }; FILTER: { data: Record<string, unknown>[]; query: string }; PARSE_CSV: { content: string }; } interface WorkerResponse { SORT_DONE: number[]; FILTER_DONE: Record<string, unknown>[]; PARSE_CSV_DONE: Record<string, string>[]; ERROR: { message: string }; } class TypedWorker { private worker: Worker; private pending = new Map<string, { resolve: Function; reject: Function }>(); private seq = 0; constructor(workerUrl: URL) { this.worker = new Worker(workerUrl, { type: 'module' }); this.worker.onmessage = ({ data }) => { const { id, type, payload } = data; const handler = this.pending.get(id); if (!handler) return; this.pending.delete(id); if (type === 'ERROR') handler.reject(new Error(payload.message)); else handler.resolve(payload); }; } send<K extends keyof WorkerRequest>(type: K, payload: WorkerRequest[K]): Promise<WorkerResponse[`${K}_DONE` & keyof WorkerResponse]> { return new Promise((resolve, reject) => { const id = String(++this.seq); this.pending.set(id, { resolve, reject }); this.worker.postMessage({ id, type, payload }); }); } terminate() { this.worker.terminate(); } } 

Передача великих даних: Transferable Objects

postMessage копіює дані за замовчуванням. Для великих ArrayBuffer це дорого. Transferable Objects передаються за посиланням (owner transfer), без копіювання:

const buffer = new ArrayBuffer(1024 * 1024 * 10); // 10 MB const view = new Float32Array(buffer); // Заповнюємо даними... // Передаємо без копіювання — після цього buffer у main thread недоступний worker.postMessage({ type: 'PROCESS', payload: buffer }, [buffer]); // У Worker self.onmessage = (event: MessageEvent) => { const buf = event.data.payload as ArrayBuffer; const view = new Float32Array(buf); // обробляємо... ctx.postMessage({ type: 'DONE', payload: buf }, [buf]); }; 

Transferable: ArrayBuffer, MessagePort, ImageBitmap, OffscreenCanvas, ReadableStream, WritableStream.

OffscreenCanvas — рендеринг у Worker

// main.ts const canvas = document.getElementById('chart') as HTMLCanvasElement; const offscreen = canvas.transferControlToOffscreen(); worker.postMessage({ type: 'INIT_CANVAS', canvas: offscreen }, [offscreen]); worker.postMessage({ type: 'RENDER', data: chartData }); // chart-worker.ts let ctx: OffscreenCanvasRenderingContext2D; self.onmessage = (event: MessageEvent) => { const { type, canvas, data } = event.data; if (type === 'INIT_CANVAS') { ctx = canvas.getContext('2d')!; return; } if (type === 'RENDER') renderChart(ctx, data); }; 

Пул Worker-ів для паралельної обробки

class WorkerPool { private workers: Worker[] = []; private queue: Array<{ resolve: Function; reject: Function; message: unknown }> = []; private idle: Worker[] = []; constructor(workerUrl: URL, poolSize = navigator.hardwareConcurrency || 4) { for (let i = 0; i < poolSize; i++) { const worker = new Worker(workerUrl, { type: 'module' }); worker.onmessage = (event) => this.onWorkerMessage(worker, event); worker.onerror = (error) => this.onWorkerError(worker, error); this.workers.push(worker); this.idle.push(worker); } } execute(message: unknown): Promise<unknown> { return new Promise((resolve, reject) => { const task = { resolve, reject, message }; const worker = this.idle.pop(); if (worker) this.dispatch(worker, task); else this.queue.push(task); }); } private dispatch(worker: Worker, task: { resolve: Function; reject: Function; message: unknown }) { (worker as any).__resolve = task.resolve; (worker as any).__reject = task.reject; worker.postMessage(task.message); } private onWorkerMessage(worker: Worker, event: MessageEvent) { (worker as any).__resolve?.(event.data); this.scheduleNext(worker); } private onWorkerError(worker: Worker, error: ErrorEvent) { (worker as any).__reject?.(new Error(error.message)); this.scheduleNext(worker); } private scheduleNext(worker: Worker) { const next = this.queue.shift(); if (next) this.dispatch(worker, next); else this.idle.push(worker); } terminate() { this.workers.forEach((w) => w.terminate()); } } 

Як забезпечити відмовостійкість при багатопотоковості?

Падіння Worker-а не повинно впливати на основний додаток. Для цього планувальник перезапускає впалий Worker і перерозподіляє задачі. У пулі використовуємо паттерн heartbeat: кожен Worker відправляє сигнал раз на 10 секунд. Якщо сигнал відсутній 20 секунд — Worker вважається впалим і замінюється новим. Це дає uptime 99,9% при штатних навантаженнях.

Параметр Одиночний Worker Пул Worker-ів
Час обробки 100 задач по 100ms ~10 сек (послідовно) ~1.2 сек (8 Workers)
Відмовостійкість Низька (падіння = втрата) Висока (перезапуск)
Використання пам'яті Мінімальне (1 потік) Помірне (за кількістю потоків)

Що входить у роботу

  • Аналіз вузьких місць у поточному додатку (профілювання, Core Web Vitals).
  • Проектування архітектури: вибір кількості Worker-ів, схеми передачі даних, стратегії fallback для старих браузерів.
  • Реалізація типізованих обгорток і пулу (або інтеграція з React/Vue через кастомні хуки).
  • Покриття unit-тестами (мокінг Worker-ів ізольовано).
  • Документація та навчання команди.
  • Гарантія підтримки та доопрацювань протягом місяця після здачі.

Етапи роботи

  1. Аудит — профілювання поточної продуктивності, виявлення кандидатів для винесення.
  2. Проектування — вибір патерну (один Worker, пул, OffscreenCanvas), визначення контрактів повідомлень.
  3. Реалізація — написання Worker-ів, інтеграція, типізація.
  4. Тестування — юніт-тести, навантажувальне тестування (імітація 20+ одночасних задач).
  5. Деплой та моніторинг — впровадження, відстеження LCP/INP після релізу.

Чому обирають нас?

Ми — команда інженерів з 10+ років досвіду у веб-розробці. Реалізували 50+ проєктів з Web Workers — від парсингу логів на клієнті до real-time дашбордів з OffscreenCanvas. Наші рішення прискорюють обчислення у 3–5 разів без втрати стабільності. Зв'яжіться з нами — ми оцінимо ваш проєкт і запропонуємо терміни від 1 до 5 днів залежно від складності. Замовте впровадження Web Workers прямо зараз.