2024-12-10 12:56:00 +08:00

82 lines
2.0 KiB
TypeScript

import { defineStore } from 'pinia';
import { reactive, ref } from 'vue';
export type BackgroundURL = string | undefined;
export type BackgroundOptions = {
resolveTiming: 'transitionStart' | 'transitionEnd';
};
export type BackgroundTask = {
url: BackgroundURL;
options: BackgroundOptions;
addFuture: PromiseWithResolvers<void>;
};
export class CancelledError extends Error {}
export const useBackgroundStore = defineStore('background', () => {
const taskQueue = reactive<BackgroundTask[]>([]);
const getFuturesMap = new Map<number, PromiseWithResolvers<BackgroundTask>>();
const maxCompId = ref(0);
function getURL(id: number) {
const future = Promise.withResolvers<BackgroundTask>();
if (taskQueue.length) {
future.resolve(taskQueue.shift()!);
} else {
getFuturesMap.set(id, future);
}
return future.promise;
}
function addURL(
url: BackgroundURL,
options: BackgroundOptions = { resolveTiming: 'transitionEnd' }
) {
const addFuture = Promise.withResolvers<void>();
// addFuture.promise.then(() => console.log('resolve', getFuturesMap));
// addFuture.promise.catch(() => console.log('reject', getFuturesMap));
const task: BackgroundTask = {
url,
options,
addFuture: addFuture
};
if (getFuturesMap.size) {
const [[id, getFuture]] = getFuturesMap;
getFuturesMap.delete(id);
getFuture.resolve(task);
} else {
taskQueue.push(task);
}
return addFuture.promise;
}
function newCompId() {
return maxCompId.value++;
}
function unregisterComp(id: number) {
getFuturesMap.get(id)?.reject(new CancelledError());
getFuturesMap.delete(id);
}
function $reset() {
for (const task of taskQueue) {
task.addFuture.reject(new CancelledError());
}
taskQueue.splice(0);
console.log(taskQueue);
for (const id of [...getFuturesMap.keys()]) {
unregisterComp(id);
}
}
return {
taskQueue: taskQueue,
getURL,
addURL,
newCompId,
unregisterComp,
$reset
};
});