Пул воркеров
createWorkerPool() (vue-worker-kit/pool) — для множества мелких независимых задач (изменение размера сотен изображений и т. п.).
import { createWorkerPool } from 'vue-worker-kit/pool'
const pool = createWorkerPool<typeof import('./resize.worker')>(
() => new Worker(new URL('./resize.worker.ts', import.meta.url), { type: 'module' }),
)
// Заранее создать все воркеры до размера пула (опционально, избегает задержки холодного старта на первых задачах)
await pool.warmup()
// Обработка массива с передачей по элементу и глобальным сигналом отмены
const thumbnails = await pool.map(files, {
concurrency: 4,
transfer: (file) => [file.buffer], // zero-copy для каждого элемента
signal: abortController.signal, // отменить все выполняющиеся задачи
})
const one = await pool.run(files[0])Воркеры создаются лениво, до size, по мере поступления задач — не все сразу. size (опция) по умолчанию равен navigator.hardwareConcurrency — собственному числу логических ядер/потоков браузера на машине, где реально работает ваше приложение, а не числу, выбранному на этапе разработки. Передайте size явно, чтобы переопределить его (например, ограничить, или если navigator сообщает то, чему вы не доверяете — некоторые браузеры с усиленной приватностью ограничивают или округляют это значение). Откатывается к 4 там, где navigator не существует (SSR).
Методы
pool.run(input, options?)
(input: In, options?: RunOptions) => Promise<Out>
Ставит задачу в очередь первому свободному воркеру.
transfer?: Transferable[]— список zero-copy передачи для этой задачиsignal?: AbortSignal— отменяет эту задачуonProgress?: (value: number) => void— получает вызовыctx.reportProgress()этой задачиonChunk?: (chunk: unknown) => void— получает вызовыctx.reportChunk()этой задачи
pool.map(items, options?)
(items: In[], options?: MapOptions) => Promise<Out[]>
Обрабатывает массив с ограниченным параллелизмом, результаты в порядке входных данных.
concurrency?: number— максимум параллельных задач (по умолчанию:pool.size)transfer?: (item: T) => Transferable[]— функция передачи zero-copy для каждого элементаsignal?: AbortSignal— глобальный сигнал отмены для всех элементовonProgress?: (value: number) => void— один callback, общий для всех элементов пакетаonChunk?: (chunk: unknown) => void— один callback, общий для всех элементов пакета
Отчёты о прогрессе и чанках
В отличие от useWorker()/useSharedWorker(), у пула нет постоянного ref progress/chunks — одновременно может выполняться множество задач в разных слотах, поэтому нет единого значения, которое можно было бы предоставить. Вместо этого передавайте onProgress/onChunk напрямую в pool.run() или pool.map():
await pool.run(input, {
onProgress: (value) => console.log('прогресс', value),
onChunk: (chunk) => console.log('чанк', chunk),
})
await pool.map(items, {
onProgress: (value) => console.log('прогресс', value), // срабатывает для того элемента, который сейчас отчитывается
onChunk: (chunk) => console.log('чанк', chunk),
})Для map() одна и та же пара onProgress/onChunk общая для всего пакета — callback'а на каждый элемент отдельно нет, поэтому если нужно знать, какому элементу принадлежит конкретное значение прогресса или чанк, эту информацию нужно закладывать в само значение/чанк (например, обработчику воркера включать в отчёт входные данные или id).
Обработчик, написанный для useWorker()/useSharedWorker() и вызывающий ctx.reportProgress()/ctx.reportChunk(), без изменений работает и под пулом — он не знает, какой composable им управляет, — но эти вызовы можно наблюдать, только если передать onProgress/onChunk в RunOptions/MapOptions; иначе они отбрасываются (см. Потоковая передача результатов — там же описано предупреждение в режиме разработки, которое в этом случае выводится).
pool.stats
ComputedRef<{ busy: number; idle: number; queued: number }>
Реактивно, используется панелью devtools.
pool.terminate()
() => void
Завершает весь пул.
pool.warmup()
() => Promise<void>
Заранее создаёт все воркеры до size, не выполняя задачи.
Вариант для Vue-composable
useWorkerPool()
Тот же API, что и у createWorkerPool(), но с автоматическим завершением через onScopeDispose для использования прямо в setup() — используйте этот вариант, когда время жизни пула должно совпадать с временем жизни компонента.