or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-scheduling.mdindex.mdpriority-management.mdprofiling.mdtesting-utilities.mdtiming-yielding.md

timing-yielding.mddocs/

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