0
# Timing and Yielding
1
2
Utilities for controlling when the scheduler yields control to the browser and managing frame rates for optimal performance.
3
4
## Capabilities
5
6
### Should Yield
7
8
Determines whether the scheduler should yield control back to the browser's main thread.
9
10
```javascript { .api }
11
/**
12
* Check if the scheduler should yield control to the browser
13
* @returns true if the scheduler should yield, false otherwise
14
*/
15
function unstable_shouldYield(): boolean;
16
```
17
18
This function helps implement cooperative scheduling by indicating when the current time slice has been exhausted. Tasks should check this periodically during long-running operations.
19
20
**Usage Examples:**
21
22
```javascript
23
import { unstable_shouldYield } from "scheduler";
24
25
// Process large dataset with yielding
26
function processLargeArray(items) {
27
const results = [];
28
29
for (let i = 0; i < items.length; i++) {
30
// Process current item
31
results.push(processItem(items[i]));
32
33
// Yield if we've used up our time slice
34
if (unstable_shouldYield()) {
35
// Return continuation to finish remaining work
36
return () => {
37
return processLargeArray(items.slice(i + 1));
38
};
39
}
40
}
41
42
return results; // All work completed
43
}
44
45
// Use within scheduled callback
46
import { unstable_scheduleCallback, unstable_NormalPriority } from "scheduler";
47
48
unstable_scheduleCallback(unstable_NormalPriority, function processWork(didTimeout) {
49
let workCompleted = 0;
50
51
while (workQueue.length > 0 && !unstable_shouldYield()) {
52
const workItem = workQueue.shift();
53
performWork(workItem);
54
workCompleted++;
55
}
56
57
console.log(`Completed ${workCompleted} items this slice`);
58
59
// Continue if more work remains
60
if (workQueue.length > 0) {
61
return processWork;
62
}
63
});
64
```
65
66
### Now
67
68
Returns the current high-resolution timestamp, similar to `performance.now()`.
69
70
```javascript { .api }
71
/**
72
* Get current high-resolution timestamp
73
* @returns Current time in milliseconds with sub-millisecond precision
74
*/
75
function unstable_now(): number;
76
```
77
78
**Usage Examples:**
79
80
```javascript
81
import { unstable_now } from "scheduler";
82
83
// Measure execution time
84
const startTime = unstable_now();
85
performExpensiveOperation();
86
const endTime = unstable_now();
87
console.log(`Operation took ${endTime - startTime}ms`);
88
89
// Implement custom timeout logic
90
function processWithTimeout(maxDuration) {
91
const startTime = unstable_now();
92
93
while (hasMoreWork()) {
94
processWorkItem();
95
96
// Check if we've exceeded our time budget
97
if (unstable_now() - startTime > maxDuration) {
98
console.log("Timeout reached, yielding");
99
break;
100
}
101
}
102
}
103
104
// Track performance metrics
105
const performanceMetrics = {
106
taskStartTime: null,
107
108
startTask() {
109
this.taskStartTime = unstable_now();
110
},
111
112
endTask() {
113
const duration = unstable_now() - this.taskStartTime;
114
console.log(`Task completed in ${duration}ms`);
115
}
116
};
117
```
118
119
### Request Paint
120
121
Signals to the scheduler that a paint is needed, which may influence yielding decisions.
122
123
```javascript { .api }
124
/**
125
* Request that the browser paint soon
126
* May influence the scheduler's yielding behavior
127
*/
128
function unstable_requestPaint(): void;
129
```
130
131
**Usage Examples:**
132
133
```javascript
134
import { unstable_requestPaint, unstable_scheduleCallback, unstable_NormalPriority } from "scheduler";
135
136
// Request paint after visual updates
137
function updateMultipleElements() {
138
unstable_scheduleCallback(unstable_NormalPriority, () => {
139
// Update DOM elements
140
updateElement1();
141
updateElement2();
142
updateElement3();
143
144
// Signal that visual changes were made
145
unstable_requestPaint();
146
});
147
}
148
149
// Use in animation loops
150
function animationStep() {
151
unstable_scheduleCallback(unstable_NormalPriority, function animate(didTimeout) {
152
// Update animation state
153
updateAnimationFrame();
154
155
// Request paint to show changes
156
unstable_requestPaint();
157
158
// Continue animation if not complete
159
if (animationRunning) {
160
return animate;
161
}
162
});
163
}
164
165
// Batch DOM updates and request paint
166
function batchDOMUpdates(updates) {
167
unstable_scheduleCallback(unstable_NormalPriority, () => {
168
updates.forEach(update => {
169
applyDOMUpdate(update);
170
});
171
172
// All DOM changes complete, request paint
173
unstable_requestPaint();
174
});
175
}
176
```
177
178
### Force Frame Rate
179
180
Forces the scheduler to target a specific frame rate by adjusting the yielding interval.
181
182
```javascript { .api }
183
/**
184
* Force scheduler to target a specific frame rate
185
* @param fps - Target frames per second (0-125), or 0 to reset to default
186
*/
187
function unstable_forceFrameRate(fps: number): void;
188
```
189
190
**Usage Examples:**
191
192
```javascript
193
import { unstable_forceFrameRate } from "scheduler";
194
195
// Set 30 FPS for performance-constrained environments
196
unstable_forceFrameRate(30);
197
198
// Set 60 FPS for smooth animations
199
unstable_forceFrameRate(60);
200
201
// Reset to default frame rate (browser-dependent, typically 60 FPS)
202
unstable_forceFrameRate(0);
203
204
// Adaptive frame rate based on device capabilities
205
function setAdaptiveFrameRate() {
206
const isLowEndDevice = navigator.hardwareConcurrency <= 2;
207
const targetFPS = isLowEndDevice ? 30 : 60;
208
209
unstable_forceFrameRate(targetFPS);
210
console.log(`Frame rate set to ${targetFPS} FPS`);
211
}
212
213
// Frame rate for specific scenarios
214
function enterGameMode() {
215
unstable_forceFrameRate(60); // Smooth gaming experience
216
}
217
218
function enterPowerSaveMode() {
219
unstable_forceFrameRate(15); // Conserve battery
220
}
221
222
function exitSpecialMode() {
223
unstable_forceFrameRate(0); // Reset to default
224
}
225
```
226
227
## Yielding Behavior
228
229
The scheduler's yielding behavior is controlled by several factors:
230
231
1. **Time Slice Duration**: Default 5ms, adjustable via `unstable_forceFrameRate`
232
2. **Paint Requests**: `unstable_requestPaint` may cause earlier yielding
233
3. **Priority Levels**: Different priorities have different timeout behaviors
234
4. **Browser Events**: High-priority browser events may trigger yielding
235
236
## Performance Considerations
237
238
### Optimal Yielding Patterns
239
240
```javascript
241
// Good: Check shouldYield in loops
242
function processItems(items) {
243
for (let i = 0; i < items.length; i++) {
244
processItem(items[i]);
245
246
if (unstable_shouldYield()) {
247
// Yield and continue with remaining items
248
return () => processItems(items.slice(i + 1));
249
}
250
}
251
}
252
253
// Good: Use requestPaint after visual updates
254
function updateVisuals() {
255
updateDOM();
256
unstable_requestPaint(); // Ensure changes are painted
257
}
258
259
// Avoid: Not checking shouldYield in long operations
260
function badProcessItems(items) {
261
// This blocks the main thread
262
for (let i = 0; i < items.length; i++) {
263
processItem(items[i]); // No yielding check
264
}
265
}
266
```
267
268
### Frame Rate Guidelines
269
270
- **60 FPS**: Smooth animations and interactions
271
- **30 FPS**: Acceptable for most content, conserves resources
272
- **15 FPS**: Power saving mode, minimal interactivity
273
- **0 (default)**: Let browser determine optimal frame rate
274
275
## Integration with Browser APIs
276
277
The scheduler integrates with various browser timing APIs:
278
279
- **`performance.now()`**: Used internally by `unstable_now()`
280
- **`MessageChannel`**: Primary scheduling mechanism in browsers
281
- **`setTimeout`**: Fallback scheduling mechanism
282
- **`setImmediate`**: Used in Node.js environments when available