Web Workers позволяют выполнять тяжёлые вычисления в отдельном потоке, не блокируя основной поток пользовательского интерфейса. В контексте Vue.js их использование повышает отзывчивость приложений, особенно при работе с большими массивами данных, сложными вычислениями или обработкой графики.
Web Worker создаётся через конструктор Worker, которому
передаётся путь к отдельному JavaScript-файлу:
// src/workers/myWorker.js
self.onmess age = function(e) {
const data = e.data;
const result = data.map(x => x * 2); // пример обработки
self.postMessage(result);
};
В Vue-компоненте Web Worker можно подключить следующим образом:
<script>
export default {
data() {
return {
numbers: [1, 2, 3, 4, 5],
results: []
};
},
mounted() {
const worker = new Worker(new URL('../workers/myWorker.js', import.meta.url));
worker.postMessage(this.numbers);
worker.onmess age = (e) => {
this.results = e.data;
worker.terminate();
};
}
};
</script>
Ключевые моменты:
new URL(..., import.meta.url) для
корректного пути при сборке через Vite.terminate() для освобождения ресурсов.Vue.js использует реактивную систему, и данные, изменённые в worker,
должны корректно интегрироваться с реактивными переменными. Передача
данных через postMessage позволяет обновлять реактивное
состояние без потери производительности:
worker.onmess age = (e) => {
this.$set(this.results, 0, e.data[0]); // обновление части массива
};
Метод $set необходим при изменении элементов массивов
или объектов, чтобы Vue корректно отслеживал изменения.
Для повторного использования логики работы с Web Worker удобно создавать composable:
// src/composables/useWorker.js
import { ref } from 'vue';
export function useWorker(workerPath) {
const result = ref(null);
const startWorker = (payload) => {
const worker = new Worker(new URL(workerPath, import.meta.url));
worker.postMessage(payload);
worker.onmess age = (e) => {
result.value = e.data;
worker.terminate();
};
return worker;
};
return { result, startWorker };
}
Применение в компоненте:
<script setup>
import { useWorker } from '../composables/useWorker.js';
const { result, startWorker } = useWorker('../workers/myWorker.js');
const numbers = [1, 2, 3, 4, 5];
startWorker(numbers);
</script>
<template>
<div>
<p>Результат: {{ result }}</p>
</div>
</template>
Преимущества подхода:
ref.Web Worker поддерживает событие onerror для отлова
ошибок:
worker.oner ror = (err) => {
console.error('Worker error:', err.message);
};
Можно также использовать onmessageerror для обработки
некорректных сообщений.
Web Worker удобно интегрировать с глобальным состоянием:
import { useStore } from 'vuex';
const store = useStore();
const worker = new Worker(new URL('../workers/myWorker.js', import.meta.url));
worker.onmess age = (e) => {
store.commit('setResults', e.data);
};
При работе с Pinia:
import { useResultsStore } from '../stores/resultsStore';
const resultsStore = useResultsStore();
worker.onmess age = (e) => {
resultsStore.results = e.data;
};
Важное замечание: все изменения состояния должны происходить в основном потоке, worker не имеет прямого доступа к Vuex или Pinia.
Transferable Objects (например, ArrayBuffer)
для передачи данных без копирования.const buffer = new ArrayBuffer(1024 * 1024);
worker.postMessage(buffer, [buffer]); // передача без копирования
Web Worker идеально подходит для асинхронных операций:
worker.onmess age = async (e) => {
const processed = await processData(e.data); // асинхронная функция в основном потоке
this.results = processed;
};
Таким образом, тяжелые вычисления остаются в отдельном потоке, а асинхронная логика может использовать реактивные данные Vue.js без блокировки интерфейса.