🚀 demo page workerize load
This commit is contained in:
@@ -1,18 +1,17 @@
|
|||||||
import { getBestRoute } from "@snk/solver/getBestRoute";
|
|
||||||
import { Color, copyGrid, Grid } from "@snk/types/grid";
|
import { Color, copyGrid, Grid } from "@snk/types/grid";
|
||||||
import { step } from "@snk/solver/step";
|
import { step } from "@snk/solver/step";
|
||||||
import { isStableAndBound, stepSpring } from "./springUtils";
|
import { isStableAndBound, stepSpring } from "./springUtils";
|
||||||
import { Res } from "@snk/github-user-contribution";
|
import type { Res } from "@snk/github-user-contribution";
|
||||||
import { Snake } from "@snk/types/snake";
|
import type { Snake } from "@snk/types/snake";
|
||||||
import {
|
import {
|
||||||
drawLerpWorld,
|
drawLerpWorld,
|
||||||
getCanvasWorldSize,
|
getCanvasWorldSize,
|
||||||
Options,
|
Options,
|
||||||
} from "@snk/draw/drawWorld";
|
} from "@snk/draw/drawWorld";
|
||||||
import { userContributionToGrid } from "../action/userContributionToGrid";
|
import { userContributionToGrid } from "@snk/action/userContributionToGrid";
|
||||||
import { snake4 as snake } from "@snk/types/__fixtures__/snake";
|
|
||||||
import { getPathToPose } from "@snk/solver/getPathToPose";
|
|
||||||
import { createSvg } from "@snk/svg-creator";
|
import { createSvg } from "@snk/svg-creator";
|
||||||
|
import { createRpcClient } from "./worker-utils";
|
||||||
|
import type { API as WorkerAPI } from "./demo.interactive.worker";
|
||||||
|
|
||||||
const createForm = ({
|
const createForm = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
@@ -47,15 +46,24 @@ const createForm = ({
|
|||||||
|
|
||||||
form.addEventListener("submit", (event) => {
|
form.addEventListener("submit", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onSubmit(input.value).catch((err) => {
|
|
||||||
label.innerText = "error :(";
|
onSubmit(input.value)
|
||||||
throw err;
|
.finally(() => {
|
||||||
});
|
clearTimeout(timeout);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
label.innerText = "error :(";
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
input.disabled = true;
|
input.disabled = true;
|
||||||
submit.disabled = true;
|
submit.disabled = true;
|
||||||
form.appendChild(label);
|
form.appendChild(label);
|
||||||
label.innerText = "loading ...";
|
label.innerText = "loading ...";
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
label.innerText = "loading ( it might take a while ) ... ";
|
||||||
|
}, 5000);
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -75,6 +83,7 @@ const createGithubProfile = () => {
|
|||||||
container.style.opacity = "0";
|
container.style.opacity = "0";
|
||||||
container.style.display = "flex";
|
container.style.display = "flex";
|
||||||
container.style.flexDirection = "column";
|
container.style.flexDirection = "column";
|
||||||
|
container.style.height = "120px";
|
||||||
container.style.alignItems = "flex-start";
|
container.style.alignItems = "flex-start";
|
||||||
const image = document.createElement("img");
|
const image = document.createElement("img");
|
||||||
image.style.width = "100px";
|
image.style.width = "100px";
|
||||||
@@ -232,13 +241,24 @@ const onSubmit = async (userName: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const grid = userContributionToGrid(cells, colorScheme);
|
const grid = userContributionToGrid(cells, colorScheme);
|
||||||
const chain = getBestRoute(grid, snake)!;
|
|
||||||
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
|
const chain = await getChain(grid);
|
||||||
|
|
||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
createViewer({ grid0: grid, chain, drawOptions });
|
createViewer({ grid0: grid, chain, drawOptions });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const worker = new Worker(
|
||||||
|
new URL(
|
||||||
|
"./demo.interactive.worker.ts",
|
||||||
|
// @ts-ignore
|
||||||
|
import.meta.url
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const { getChain } = createRpcClient<WorkerAPI>(worker);
|
||||||
|
|
||||||
const profile = createGithubProfile();
|
const profile = createGithubProfile();
|
||||||
const { dispose } = createForm({
|
const { dispose } = createForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
|||||||
17
packages/demo/demo.interactive.worker.ts
Normal file
17
packages/demo/demo.interactive.worker.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { getBestRoute } from "@snk/solver/getBestRoute";
|
||||||
|
import { getPathToPose } from "@snk/solver/getPathToPose";
|
||||||
|
import { snake4 as snake } from "@snk/types/__fixtures__/snake";
|
||||||
|
import type { Grid } from "@snk/types/grid";
|
||||||
|
import { createRpcServer } from "./worker-utils";
|
||||||
|
|
||||||
|
const getChain = (grid: Grid) => {
|
||||||
|
const chain = getBestRoute(grid, snake)!;
|
||||||
|
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
};
|
||||||
|
|
||||||
|
const api = { getChain };
|
||||||
|
export type API = typeof api;
|
||||||
|
|
||||||
|
createRpcServer(api);
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"name": "@snk/demo",
|
"name": "@snk/demo",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@snk/action": "1.0.0",
|
||||||
"@snk/draw": "1.0.0",
|
"@snk/draw": "1.0.0",
|
||||||
"@snk/github-user-contribution": "1.0.0",
|
"@snk/github-user-contribution": "1.0.0",
|
||||||
"@snk/solver": "1.0.0",
|
"@snk/solver": "1.0.0",
|
||||||
|
|||||||
59
packages/demo/worker-utils.ts
Normal file
59
packages/demo/worker-utils.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
type API = Record<string, (...args: any[]) => any>;
|
||||||
|
|
||||||
|
const symbol = "worker-rpc__";
|
||||||
|
|
||||||
|
export const createRpcServer = (api: API) =>
|
||||||
|
self.addEventListener("message", async (event) => {
|
||||||
|
if (event.data?.symbol === symbol) {
|
||||||
|
try {
|
||||||
|
const res = await api[event.data.methodName](...event.data.args);
|
||||||
|
self.postMessage({ symbol, key: event.data.key, res });
|
||||||
|
} catch (error: any) {
|
||||||
|
postMessage({ symbol, key: event.data.key, error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createRpcClient = <API_ extends API>(worker: Worker) => {
|
||||||
|
const originalTerminate = worker.terminate;
|
||||||
|
worker.terminate = () => {
|
||||||
|
worker.dispatchEvent(new Event("terminate"));
|
||||||
|
originalTerminate.call(worker);
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Proxy(
|
||||||
|
{} as {
|
||||||
|
[K in keyof API_]: (
|
||||||
|
...args: Parameters<API_[K]>
|
||||||
|
) => Promise<Awaited<ReturnType<API_[K]>>>;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
get:
|
||||||
|
(_, methodName) =>
|
||||||
|
(...args: any[]) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const key = Math.random().toString();
|
||||||
|
|
||||||
|
const onTerminate = () => {
|
||||||
|
worker.removeEventListener("terminate", onTerminate);
|
||||||
|
worker.removeEventListener("message", onMessageHandler);
|
||||||
|
reject(new Error("worker terminated"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMessageHandler = (event: MessageEvent) => {
|
||||||
|
if (event.data?.symbol === symbol && event.data.key === key) {
|
||||||
|
if (event.data.error) reject(event.data.error);
|
||||||
|
else if (event.data.res) resolve(event.data.res);
|
||||||
|
|
||||||
|
worker.removeEventListener("terminate", onTerminate);
|
||||||
|
worker.removeEventListener("message", onMessageHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
worker.addEventListener("message", onMessageHandler);
|
||||||
|
worker.addEventListener("terminate", onTerminate);
|
||||||
|
worker.postMessage({ symbol, key, methodName, args });
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user