From e5bc74e4525fe528f49150460f8a80a610abf5e8 Mon Sep 17 00:00:00 2001 From: BEERINHO Date: Fri, 26 Apr 2024 16:27:57 +0200 Subject: [PATCH] Add keep_latest --- src/lib/handlers/keep_latest.ts | 44 ++++++++++++++ src/lib/task.ts | 2 + src/lib/tests/components/keep_latest.svelte | 65 +++++++++++++++++++++ src/lib/tests/task.test.ts | 33 +++++++++++ src/routes/+page.svelte | 36 ++++++++++++ 5 files changed, 180 insertions(+) create mode 100644 src/lib/handlers/keep_latest.ts create mode 100644 src/lib/tests/components/keep_latest.svelte diff --git a/src/lib/handlers/keep_latest.ts b/src/lib/handlers/keep_latest.ts new file mode 100644 index 0000000..9da5a11 --- /dev/null +++ b/src/lib/handlers/keep_latest.ts @@ -0,0 +1,44 @@ +import type { Handler } from './types'; + +type Handle = ReturnType; +type Fn = Parameters[0]; +type Utils = Parameters[1]; + +const handler = (() => { + let is_running = false; + let queue: + | { + fn: Fn; + utils: Utils; + } + | undefined; + + const handle: Handle = async (fn: () => void, utils) => { + if (is_running) { + queue?.utils.abort_controller.abort(); + queue = { + fn, + utils, + }; + return; + } + is_running = true; + + try { + fn(); + await utils.promise; + } catch { + /** empty */ + } + + const next = queue; + is_running = false; + queue = undefined; + if (next) { + handle(next.fn, next.utils); + } + }; + return handle; +}) satisfies Handler; + +export default handler; diff --git a/src/lib/task.ts b/src/lib/task.ts index 5c5bb4c..616f8b9 100644 --- a/src/lib/task.ts +++ b/src/lib/task.ts @@ -4,12 +4,14 @@ import { writable } from 'svelte/store'; import default_handler from './handlers/default'; import drop from './handlers/drop'; import enqueue from './handlers/enqueue'; +import keep_latest from './handlers/keep_latest'; import restart from './handlers/restart'; const handlers = { default: default_handler, drop, enqueue, + keep_latest, restart, } as const; diff --git a/src/lib/tests/components/keep_latest.svelte b/src/lib/tests/components/keep_latest.svelte new file mode 100644 index 0000000..8d21486 --- /dev/null +++ b/src/lib/tests/components/keep_latest.svelte @@ -0,0 +1,65 @@ + + + + + + + + + + + + + diff --git a/src/lib/tests/task.test.ts b/src/lib/tests/task.test.ts index 087a10d..ca66c86 100644 --- a/src/lib/tests/task.test.ts +++ b/src/lib/tests/task.test.ts @@ -8,6 +8,7 @@ import Default from './components/default.svelte'; import Enqueue from './components/enqueue.svelte'; import Drop from './components/drop.svelte'; import Restart from './components/restart.svelte'; +import KeepLatest from './components/keep_latest.svelte'; function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -21,6 +22,7 @@ describe.each([ { component: Default, name: 'default' }, { component: Enqueue, name: 'enqueue' }, { component: Drop, name: 'drop' }, + { component: KeepLatest, name: 'keep_latest' }, { component: Restart, name: 'restart' }, ])('task - basic functionality $name', ({ component }) => { all_options((selector) => { @@ -327,6 +329,37 @@ describe("task - specific functionality 'drop'", () => { }); }); +describe("task - specific functionality 'keep_latest'", () => { + all_options((selector) => { + it('completes only the first and the last time if multiple instances are created in between', async () => { + let finished = 0; + const fn = vi.fn(async function* () { + await wait(50); + yield; + finished++; + }); + const { getByTestId } = render(KeepLatest, { + fn, + }); + const perform = getByTestId(`perform-${selector}`); + perform.click(); + perform.click(); + perform.click(); + perform.click(); + await vi.waitFor(() => { + expect(fn).toHaveBeenCalledTimes(2); + }); + await vi.waitFor(() => { + expect(finished).toBe(2); + }); + perform.click(); + await vi.waitFor(() => { + expect(finished).toBe(3); + }); + }); + }); +}); + describe("task - specific functionality 'restart'", () => { all_options((selector) => { it('completes only `max` time if performed when other instances are already running', async () => { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a84986a..7ec6409 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -41,9 +41,16 @@ return param; }); + const latest_log = task.keep_latest(async (param: number) => { + await new Promise((r) => setTimeout(r, 2000)); + return param; + }); + let hidden = false; let x; + + let numbers: number[] = [];
@@ -100,6 +107,35 @@
+
+ latest_log +
{JSON.stringify($latest_log, null, '	')}
+ + + +
    + {#each numbers as number} +
  • + {number} +
  • + {/each} +
+
+