Этот вопрос исследует методы выполнения JavaScript кода в фоновых потоках для избежания блокировки основного потока.
Для выноса выполнения скрипта в отдельный поток можно использовать Web Workers для параллельного выполнения, Service Workers для фоновых задач, или Worker Threads в Node.js. Также можно использовать setTimeout и setImmediate для разбивки тяжелых задач на части, или requestIdleCallback для выполнения во время простоя браузера.
Различные API позволяют выполнять код вне основного потока для улучшения производительности.
1. Web Workers:
Создание worker:
// main.js
const worker = new Worker('worker.js');
// Отправка данных в worker
worker.postMessage({ type: 'process', data: largeArray });
// Получение результатов
worker.onmessage = (event) => {
console.log('Result from worker:', event.data);
};
// Обработка ошибок
worker.onerror = (error) => {
console.error('Worker error:', error);
};worker.js:
// Обработка сообщений из основного потока
self.onmessage = function(event) {
const { type, data } = event.data;
if (type === 'process') {
// Тяжелые вычисления
const result = heavyComputation(data);
// Отправка результата обратно
self.postMessage(result);
}
};
function heavyComputation(data) {
// Вычисления, которые не блокируют основной поток
return data.map(item => item * 2);
}2. Service Workers:
Регистрация:
// Регистрация service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker registered');
});
}
// sw.js - кэширование и фоновые задачи
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});3. Worker Threads в Node.js:
const { Worker } = require('worker_threads');
function runService(workerData) {
return new Promise((resolve, reject) => {
const worker = new Worker('./worker.js', { workerData });
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
}
// worker.js
const { workerData, parentPort } = require('worker_threads');
parentPort.postMessage(heavyComputation(workerData));4. Разбивка тяжелых задач:
Использование setTimeout:
function processInChunks(array, chunkSize, callback) {
let index = 0;
function processChunk() {
const chunk = array.slice(index, index + chunkSize);
// Обработка чанка
chunk.forEach(processItem);
index += chunkSize;
if (index < array.length) {
// Продолжаем в следующем frame
setTimeout(processChunk, 0);
} else {
callback();
}
}
processChunk();
}Использование requestIdleCallback:
function processDuringIdleTime(tasks) {
function processTask(deadline) {
while (tasks.length > 0 && deadline.timeRemaining() > 0) {
const task = tasks.shift();
executeTask(task);
}
if (tasks.length > 0) {
requestIdleCallback(processTask);
}
}
requestIdleCallback(processTask);
}5. OffscreenCanvas для графики:
// Рендеринг canvas в worker
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('canvas-worker.js');
worker.postMessage({ canvas: offscreen }, [offscreen]);
// canvas-worker.js
self.onmessage = function(event) {
const canvas = event.data.canvas;
const ctx = canvas.getContext('2d');
// Рендеринг без блокировки основного потока
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, canvas.width, canvas.height);
};Ограничения Workers:
Нет доступа к DOM
Ограниченный доступ к window API
Данные передаются через сообщения (serialized)
Более сложная отладка
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию