← Назад к вопросам

В чем разница между воркерами?

2.2 Middle🔥 121 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Web Workers в JavaScript: типы и различия

Воркеры — это потоки, работающие в фоне параллельно с основным потоком (main thread). Это позволяет не блокировать UI при выполнении тяжёлых операций. Существует несколько типов воркеров, каждый с собственными особенностями.

1. Web Worker (Dedicated Worker)

Обычный воркер, работающий с одним script'ом в отдельном потоке:

// main.js (основной поток)
const worker = new Worker('worker.js');

// Отправляем сообщение в worker
worker.postMessage({ task: 'heavy-computation', data: [1, 2, 3] });

// Получаем результат
worker.onmessage = (event) => {
  console.log('Result from worker:', event.data);
  // Обновляем UI
};
// worker.js (отдельный поток)
self.onmessage = (event) => {
  const { task, data } = event.data;
  
  if (task === 'heavy-computation') {
    // Тяжёлые вычисления (не блокирует UI)
    const result = data.reduce((a, b) => a + b, 0);
    
    // Отправляем результат назад
    self.postMessage({ result });
  }
};

Характеристики Web Worker:

  • Dedicated — каждый worker работает только с одним главным потоком
  • Отдельный контекст — нет доступа к DOM, window
  • Постоянно живущий — существует до явного terminate()
  • Высокие затраты — инициализация требует памяти и времени
  • Медленное сообщение — данные копируются (deep copy), не по ссылке

2. Shared Worker

Воркер, который может использоваться несколькими вкладками/окнами одного источника:

// main.js (вкладка 1 и вкладка 2 одновременно)
const sharedWorker = new SharedWorker('shared-worker.js');

// Используем port для коммуникации
sharedWorker.port.start();

sharedWorker.port.postMessage({ action: 'increment' });

sharedWorker.port.onmessage = (event) => {
  console.log('Counter:', event.data);
};
// shared-worker.js
let counter = 0;

self.onconnect = (event) => {
  const port = event.ports[0];
  port.start();
  
  port.onmessage = (event) => {
    if (event.data.action === 'increment') {
      counter++;
      // Отправляем всем подключённым вкладкам
      port.postMessage(counter);
    }
  };
};

Характеристики Shared Worker:

  • Shared — несколько контекстов могут использовать один worker
  • Требует port — коммуникация через port
  • Синхронизация — все вкладки видят одно состояние
  • Сложнее в отладке — работает с несколькими потребителями
  • Меньше поддержки — не поддерживается в Safari и IE

3. Service Worker

Специальный воркер для кэширования, offline поддержки и push-уведомлений:

// main.js
navigator.serviceWorker.register('sw.js')
  .then(reg => console.log('Service Worker registered'))
  .catch(err => console.error('Registration failed'));

// Отправляем сообщение в Service Worker
navigator.serviceWorker.controller.postMessage({ action: 'sync' });
// sw.js (Service Worker)
self.addEventListener('install', event => {
  // Кэширование ассетов при установке
  event.waitUntil(
    caches.open('v1').then(cache => {
      return cache.addAll(['/index.html', '/style.css']);
    })
  );
});

self.addEventListener('fetch', event => {
  // Перехват всех fetch'ей
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

self.addEventListener('push', event => {
  // Push-уведомления
  const data = event.data.json();
  self.registration.showNotification(data.title);
});

Характеристики Service Worker:

  • Специальный назначение — кэширование, offline, push
  • Жизненный цикл — install, activate, fetch
  • Перехват сети — может работать как proxy
  • Долгоживущий — сохраняется между сеансами
  • Требует HTTPS (кроме localhost)

4. Web Worker vs Shared Worker vs Service Worker

ПараметрWeb WorkerShared WorkerService Worker
НазначениеВычисленияОбщие данныеКэширование, offline
ОбластьОдна вкладкаВсе вкладки доменаВесь домен
КоммуникацияpostMessageport.postMessagenavigator.serviceWorker
Доступ к DOMНЕТНЕТНЕТ
Доступ к StorageIndexedDBIndexedDBIndexedDB, Cache API
Требует HTTPSНЕТНЕТДА (кроме localhost)
ПоддержкаХорошаяПлохаяХорошая
СложностьНизкаяСредняяВысокая

Практические примеры

Пример 1: Тяжёлые вычисления (Web Worker)

// main.js
const computePrimes = (max) => {
  const worker = new Worker('primes.js');
  
  return new Promise((resolve) => {
    worker.postMessage(max);
    worker.onmessage = (e) => {
      resolve(e.data);
      worker.terminate(); // Очищаем память
    };
  });
};

await computePrimes(100000);
// primes.js
self.onmessage = (event) => {
  const max = event.data;
  const primes = [];
  
  for (let i = 2; i <= max; i++) {
    let isPrime = true;
    for (let j = 2; j < i; j++) {
      if (i % j === 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) primes.push(i);
  }
  
  self.postMessage(primes);
};

Пример 2: Service Worker для offline

// sw.js
const CACHE = 'my-cache-v1';

self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request)
      .then(response => {
        if (!response || response.status !== 200) {
          return response;
        }
        
        // Кэшируем успешные запросы
        const clone = response.clone();
        caches.open(CACHE).then(cache => {
          cache.put(event.request, clone);
        });
        
        return response;
      })
      .catch(() => {
        // Offline: вернём из кэша
        return caches.match(event.request);
      })
  );
});

Пример 3: Shared Worker для синхронизации

// shared-counter.js
let counter = 0;
const ports = [];

self.onconnect = (event) => {
  const port = event.ports[0];
  ports.push(port);
  port.start();
  
  port.onmessage = (e) => {
    if (e.data.action === 'increment') {
      counter++;
      // Уведомляем все вкладки
      ports.forEach(p => p.postMessage({ counter }));
    }
  };
};

Когда использовать каждый

Web Worker:

  • Факториалы, простые числа, обработка больших массивов
  • Сортировка, поиск, шифрование
  • Обработка видео/аудио
  • Вычисление graphics

Shared Worker:

  • Синхронизация состояния между вкладками
  • Multiplayer games (общая логика)
  • Real-time notifications

Service Worker:

  • Offline support
  • Кэширование стратегии
  • Background sync
  • Push-уведомления

Проблемы и решения

1. Service Worker не обновляется

// Явное обновление
navigator.serviceWorker.ready.then(reg => {
  reg.update();
});

2. Проблема с данными в Worker

// ❌ Медленно: deep copy
worker.postMessage({ largeArray: [...Array(1000000)] });

// ✅ Быстро: transferable objects
const buffer = new ArrayBuffer(data);
worker.postMessage({ buffer }, [buffer]); // Трансферируем, не копируем

Вывод

  • Web Worker — для CPU-интенсивных операций
  • Shared Worker — для синхронизации между вкладками (редко используется)
  • Service Worker — для кэширования и offline

Выбор зависит от задачи, но в 2026 году Service Worker используется чаще всего для PWA приложений.