Loading client/src/composables/filter/filter.js +43 −37 Original line number Diff line number Diff line import { toValue } from "@vueuse/core"; import { onScopeDispose, ref, watch } from "vue"; import { onScopeDispose, ref, watchEffect } from "vue"; export function useFilterObjectArray(array, filter, objectFields, asRegex = false) { const worker = new Worker(new URL("./filter.worker.js", import.meta.url)); let worker; let idCounter = 0; let workerReferenceCount = 0; const filtered = ref([]); filtered.value = toValue(array); export function useFilterObjectArray(array, filter, objectFields) { if (!worker) { worker = new Worker(new URL("./filter.worker.js", import.meta.url)); } workerReferenceCount += 1; const id = idCounter++; const post = (message) => { worker.postMessage(message); worker.postMessage({ id, ...message }); }; watch( () => toValue(array), (arr) => { post({ type: "setArray", array: arr }); }, { immediate: true, } ); watch( () => toValue(filter), (f) => { post({ type: "setFilter", filter: f }); }, { immediate: true, } ); watch( () => toValue(objectFields), (fields) => { post({ type: "setFields", fields }); }, { immediate: true, } ); const filtered = ref([]); filtered.value = toValue(array); worker.onmessage = (e) => { const onMessage = (e) => { const message = e.data; // exit if message is not meant for this composable instance if (message.id !== id) { return; } if (message.type === "result") { filtered.value = message.filtered; } else { post({ type: "clear" }); worker.removeEventListener("message", onMessage); } }; worker.addEventListener("message", onMessage); watchEffect(() => { post({ type: "setArray", array: toValue(array) }); }); watchEffect(() => { post({ type: "setFilter", filter: toValue(filter) }); }); watchEffect(() => { post({ type: "setFields", fields: toValue(objectFields) }); }); onScopeDispose(() => { workerReferenceCount -= 1; if (workerReferenceCount <= 0) { worker.terminate(); worker = null; } }); return filtered; Loading client/src/composables/filter/filter.worker.js +49 −12 Original line number Diff line number Diff line import { runFilter } from "@/composables/filter/filterFunction"; let array = []; let filter = ""; let fields = []; function createOptions() { return { array: [], filter: "", fields: [], }; } const optionsById = new Map(); const timerById = new Map(); self.addEventListener("message", (e) => { const message = e.data; if (message.type === "setArray") { array = message.array; } else if (message.type === "setFields") { fields = message.fields; } else if (message.type === "setFilter") { filter = message.filter; if (!optionsById.has(message.id)) { optionsById.set(message.id, createOptions()); } const options = optionsById.get(message.id); switch (message.type) { case "setArray": options.array = message.array; break; case "setFields": options.fields = message.fields; break; case "setFilter": options.filter = message.filter; break; case "clear": optionsById.delete(message.id); break; default: break; } if (array.length > 0 && fields.length > 0) { const filtered = runFilter(filter, array, fields); if (timerById.has(message.id)) { clearTimeout(timerById.get(message.id)); } timerById.set( message.id, setTimeout(() => { if (options.array.length > 0 && options.fields.length > 0) { const filtered = runFilter(options.filter, options.array, options.fields); self.postMessage({ type: "result", filtered }); } timerById.delete(message.id); }, 10) ); }); Loading
client/src/composables/filter/filter.js +43 −37 Original line number Diff line number Diff line import { toValue } from "@vueuse/core"; import { onScopeDispose, ref, watch } from "vue"; import { onScopeDispose, ref, watchEffect } from "vue"; export function useFilterObjectArray(array, filter, objectFields, asRegex = false) { const worker = new Worker(new URL("./filter.worker.js", import.meta.url)); let worker; let idCounter = 0; let workerReferenceCount = 0; const filtered = ref([]); filtered.value = toValue(array); export function useFilterObjectArray(array, filter, objectFields) { if (!worker) { worker = new Worker(new URL("./filter.worker.js", import.meta.url)); } workerReferenceCount += 1; const id = idCounter++; const post = (message) => { worker.postMessage(message); worker.postMessage({ id, ...message }); }; watch( () => toValue(array), (arr) => { post({ type: "setArray", array: arr }); }, { immediate: true, } ); watch( () => toValue(filter), (f) => { post({ type: "setFilter", filter: f }); }, { immediate: true, } ); watch( () => toValue(objectFields), (fields) => { post({ type: "setFields", fields }); }, { immediate: true, } ); const filtered = ref([]); filtered.value = toValue(array); worker.onmessage = (e) => { const onMessage = (e) => { const message = e.data; // exit if message is not meant for this composable instance if (message.id !== id) { return; } if (message.type === "result") { filtered.value = message.filtered; } else { post({ type: "clear" }); worker.removeEventListener("message", onMessage); } }; worker.addEventListener("message", onMessage); watchEffect(() => { post({ type: "setArray", array: toValue(array) }); }); watchEffect(() => { post({ type: "setFilter", filter: toValue(filter) }); }); watchEffect(() => { post({ type: "setFields", fields: toValue(objectFields) }); }); onScopeDispose(() => { workerReferenceCount -= 1; if (workerReferenceCount <= 0) { worker.terminate(); worker = null; } }); return filtered; Loading
client/src/composables/filter/filter.worker.js +49 −12 Original line number Diff line number Diff line import { runFilter } from "@/composables/filter/filterFunction"; let array = []; let filter = ""; let fields = []; function createOptions() { return { array: [], filter: "", fields: [], }; } const optionsById = new Map(); const timerById = new Map(); self.addEventListener("message", (e) => { const message = e.data; if (message.type === "setArray") { array = message.array; } else if (message.type === "setFields") { fields = message.fields; } else if (message.type === "setFilter") { filter = message.filter; if (!optionsById.has(message.id)) { optionsById.set(message.id, createOptions()); } const options = optionsById.get(message.id); switch (message.type) { case "setArray": options.array = message.array; break; case "setFields": options.fields = message.fields; break; case "setFilter": options.filter = message.filter; break; case "clear": optionsById.delete(message.id); break; default: break; } if (array.length > 0 && fields.length > 0) { const filtered = runFilter(filter, array, fields); if (timerById.has(message.id)) { clearTimeout(timerById.get(message.id)); } timerById.set( message.id, setTimeout(() => { if (options.array.length > 0 && options.fields.length > 0) { const filtered = runFilter(options.filter, options.array, options.fields); self.postMessage({ type: "result", filtered }); } timerById.delete(message.id); }, 10) ); });