HUGE sidebar and typing performance improvements (#516)

This commit is contained in:
Gregory Schier
2026-08-13 12:23:56 -07:00
committed by GitHub
parent b9d4f76193
commit 74d1b5d6ce
16 changed files with 620 additions and 130 deletions
+76
View File
@@ -0,0 +1,76 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { debounce } from "./debounce";
describe("debounce", () => {
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
it("calls once with the latest args after the delay", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d("a");
d("b");
d("c");
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(100);
expect(fn).toHaveBeenCalledExactlyOnceWith("c");
});
it("flush invokes a pending call immediately", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d("a");
d("b");
d.flush();
expect(fn).toHaveBeenCalledExactlyOnceWith("b");
// The scheduled call was cancelled, so waiting out the delay adds nothing
vi.advanceTimersByTime(100);
expect(fn).toHaveBeenCalledOnce();
});
it("flush is a no-op with nothing pending", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d.flush();
expect(fn).not.toHaveBeenCalled();
d("a");
vi.advanceTimersByTime(100);
d.flush();
expect(fn).toHaveBeenCalledExactlyOnceWith("a");
});
it("cancel drops the pending call and its args", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d("a");
d.cancel();
vi.advanceTimersByTime(100);
expect(fn).not.toHaveBeenCalled();
// A cancelled call must not leak its args into the next one
d.flush();
expect(fn).not.toHaveBeenCalled();
});
it("starts a fresh delay after firing", () => {
const fn = vi.fn();
const d = debounce(fn, 100);
d("a");
vi.advanceTimersByTime(100);
d("b");
vi.advanceTimersByTime(99);
expect(fn).toHaveBeenCalledOnce();
vi.advanceTimersByTime(1);
expect(fn).toHaveBeenCalledTimes(2);
expect(fn).toHaveBeenLastCalledWith("b");
});
});
+22 -3
View File
@@ -1,13 +1,32 @@
// oxlint-disable-next-line no-explicit-any
export function debounce(fn: (...args: any[]) => void, delay = 500) {
let timer: ReturnType<typeof setTimeout>;
let timer: ReturnType<typeof setTimeout> | null = null;
// oxlint-disable-next-line no-explicit-any
let lastArgs: any[] | null = null;
// oxlint-disable-next-line no-explicit-any
const result = (...args: any[]) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
lastArgs = args;
if (timer != null) clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
const argsToUse = lastArgs ?? [];
lastArgs = null;
fn(...argsToUse);
}, delay);
};
result.cancel = () => {
if (timer != null) clearTimeout(timer);
timer = null;
lastArgs = null;
};
// Invoke a pending call immediately instead of waiting out the delay
result.flush = () => {
if (timer == null) return;
clearTimeout(timer);
timer = null;
const argsToUse = lastArgs ?? [];
lastArgs = null;
fn(...argsToUse);
};
return result;
}