import { ref, onBeforeUnmount } from 'vue';
export function useWorker(
urlOrFactory,
{ autoStart = true, timeout = 0 } = {}
) {
const message = ref(null);
const error = ref(null);
const running = ref(false);
let worker = null;
let timerId = null;
function createWorker() {
if (typeof urlOrFactory === 'function') {
const code = urlOrFactory();
const blob = new Blob([code], { type: 'application/javascript' });
return new Worker(URL.createObjectURL(blob));
} else {
return new Worker(urlOrFactory);
}
}
function start() {
if (worker) return;
worker = createWorker();
running.value = true;
worker.onmessage = (e) => {
message.value = e.data;
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
};
worker.onerror = (e) => {
error.value = e;
running.value = false;
worker.terminate();
worker = null;
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
};
}
function post(data, transfer) {
if (!worker) start();
if (timeout > 0) {
timerId = setTimeout(() => {
error.value = new Error('Worker request timed out');
terminate();
}, timeout);
}
if (Array.isArray(transfer)) {
worker.postMessage(data, transfer);
} else {
worker.postMessage(data);
}
}
function terminate() {
if (worker) {
worker.terminate();
worker = null;
running.value = false;
}
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
}
onBeforeUnmount(() => {
terminate();
});
if (autoStart) start();
return { message, error, running, post, terminate };
}