Skip to content

Commit f1a986b

Browse files
committed
fix(cursors): actually do 60fps yield
1 parent 128458d commit f1a986b

1 file changed

Lines changed: 16 additions & 25 deletions

File tree

packages/qwik/src/core/shared/cursor/cursor-walker.ts

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import type { ValueOrPromise } from '../utils/types';
3333
import { assertDefined, assertFalse } from '../error/assert';
3434
import type { Container } from '../types';
3535
import { VNodeFlags } from '../../client/types';
36-
import { isBrowser, isDev, isServer } from '@qwik.dev/core/build';
36+
import { isDev, isServer } from '@qwik.dev/core/build';
3737

3838
const DEBUG = false;
3939

@@ -56,27 +56,24 @@ function scheduleYield(): void {
5656
}
5757
}
5858

59-
/** Options for walking a cursor. */
60-
export interface WalkOptions {
61-
/** Time budget in milliseconds (for DOM time-slicing). If exceeded, walk pauses. */
62-
timeBudget: number;
63-
}
64-
6559
/**
6660
* Processes the cursor queue, walking each cursor in turn.
6761
*
6862
* @param options - Walk options (time budget, etc.)
6963
*/
70-
export function processCursorQueue(
71-
options: WalkOptions = {
72-
timeBudget: 1000 / 60, // 60fps
73-
}
74-
): void {
64+
export function processCursorQueue(): void {
7565
isNextTickScheduled = false;
66+
const startTime = performance.now();
67+
const yieldTime = startTime + 15; // 16 ms = 60 FPS, use 15 to yield slightly before next frame
7668

7769
let cursor: Cursor | null = null;
7870
while ((cursor = getHighestPriorityCursor())) {
79-
walkCursor(cursor, options);
71+
if (walkCursor(cursor, yieldTime)) {
72+
// Cursor overran time budget, yield to browser
73+
// Note that each tick we process at least one thing
74+
scheduleYield();
75+
return;
76+
}
8077
}
8178
}
8279

@@ -96,13 +93,12 @@ export function processCursorQueue(
9693
* Note that there is only one walker for all containers in the app with the same Qwik version.
9794
*
9895
* @param cursor - The cursor to walk
99-
* @param options - Walk options (time budget, etc.)
100-
* @returns Walk result indicating completion status
96+
* @param until - Time budget (timestamp to yield by)
97+
* @returns `true` if the walk was paused due to time budget (do not process more cursors in this
98+
* tick)
10199
*/
102-
export function walkCursor(cursor: Cursor, options: WalkOptions): void {
103-
const { timeBudget } = options;
100+
export function walkCursor(cursor: Cursor, until: number): boolean | void {
104101
const isRunningOnServer = import.meta.env.TEST ? isServerPlatform() : isServer;
105-
const startTime = performance.now();
106102

107103
const cursorData = getCursorData(cursor)!;
108104

@@ -213,13 +209,8 @@ export function walkCursor(cursor: Cursor, options: WalkOptions): void {
213209
}
214210

215211
// Check time budget (only for DOM, not SSR)
216-
if (isBrowser) {
217-
const elapsed = performance.now() - startTime;
218-
if (elapsed >= timeBudget) {
219-
// Schedule continuation as macrotask to actually yield to browser
220-
scheduleYield();
221-
return;
222-
}
212+
if (performance.now() >= until) {
213+
return true;
223214
}
224215
}
225216
isDev &&

0 commit comments

Comments
 (0)