diff options
Diffstat (limited to 'packages/frontend/src/utility/idle-render.ts')
| -rw-r--r-- | packages/frontend/src/utility/idle-render.ts | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/packages/frontend/src/utility/idle-render.ts b/packages/frontend/src/utility/idle-render.ts new file mode 100644 index 0000000000..6adfedcb9f --- /dev/null +++ b/packages/frontend/src/utility/idle-render.ts @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +const requestIdleCallback: typeof globalThis.requestIdleCallback = globalThis.requestIdleCallback ?? ((callback) => { + const start = performance.now(); + const timeoutId = setTimeout(() => { + callback({ + didTimeout: false, // polyfill でタイムアウト発火することはない + timeRemaining() { + const diff = performance.now() - start; + return Math.max(0, 50 - diff); // <https://www.w3.org/TR/requestidlecallback/#idle-periods> + }, + }); + }); + return timeoutId; +}); +const cancelIdleCallback: typeof globalThis.cancelIdleCallback = globalThis.cancelIdleCallback ?? ((timeoutId) => { + clearTimeout(timeoutId); +}); + +class IdlingRenderScheduler { + #renderers: Set<FrameRequestCallback>; + #rafId: number; + #ricId: number; + + constructor() { + this.#renderers = new Set(); + this.#rafId = 0; + this.#ricId = requestIdleCallback((deadline) => this.#schedule(deadline)); + } + + #schedule(deadline: IdleDeadline): void { + if (deadline.timeRemaining()) { + this.#rafId = requestAnimationFrame((time) => { + for (const renderer of this.#renderers) { + renderer(time); + } + }); + } + this.#ricId = requestIdleCallback((arg) => this.#schedule(arg)); + } + + add(renderer: FrameRequestCallback): void { + this.#renderers.add(renderer); + } + + delete(renderer: FrameRequestCallback): void { + this.#renderers.delete(renderer); + } + + dispose(): void { + this.#renderers.clear(); + cancelAnimationFrame(this.#rafId); + cancelIdleCallback(this.#ricId); + } +} + +export const defaultIdlingRenderScheduler = new IdlingRenderScheduler(); |