Skip to content

Commit a8bed38

Browse files
committed
[scheduler] Priority levels, continuations, and wrapped callbacks
All of these features are based on features of React's internal scheduler. The eventual goal is to lift as much as possible out of the React internals into the Scheduler package. Includes some renaming of existing methods. - `scheduleWork` is now `scheduleCallback` - `cancelScheduledWork` is now `cancelCallback` Priority levels --------------- Adds the ability to schedule callbacks at different priority levels. The current levels are (final names TBD): - Immediate priority. Fires at the end of the outermost currently executing (similar to a microtask). - Interactive priority. Fires within a few hundred milliseconds. This should only be used to provide quick feedback to the user as a result of an interaction. - Normal priority. This is the default. Fires within several seconds. - "Maybe" priority. Only fires if there's nothing else to do. Used for prerendering or warming a cache. The priority is changed using `runWithPriority`: ```js runWithPriority(InteractivePriority, () => { scheduleCallback(callback); }); ``` Continuations ------------- Adds the ability for a callback to yield without losing its place in the queue, by returning a continuation. The continuation will have the same expiration as the callback that yielded. Wrapped callbacks ----------------- Adds the ability to wrap a callback so that, when it is called, it receives the priority of the current execution context.
1 parent 2c7b78f commit a8bed38

15 files changed

Lines changed: 905 additions & 331 deletions

File tree

fixtures/scheduler/index.html

Lines changed: 78 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<!DOCTYPE html>
22
<html style="width: 100%; height: 100%;">
3-
<head>
4-
<meta charset="utf-8">
5-
<title>Scheduler Test Page</title>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Scheduler Test Page</title>
67
<style>
78
.correct {
89
border: solid green 2px;
@@ -11,91 +12,92 @@
1112
border: dashed red 2px;
1213
}
1314
</style>
14-
</head>
15-
<body>
16-
<h1>Scheduler Fixture</h1>
17-
<p>
18-
This fixture is for manual testing purposes, and the patterns used in
19-
implementing it should not be used as a model. This is mainly for anyone
20-
working on making changes to the `schedule` module.
21-
</p>
22-
<h2>Tests:</h2>
23-
<ol>
24-
<li>
25-
<button onClick="runTestOne()">Run Test 1</button>
26-
<p>Calls the callback within the frame when not blocked:</p>
27-
<div><b>Expected:</b></div>
28-
<div id="test-1-expected">
29-
</div>
30-
<div> -------------------------------------------------</div>
31-
<div> If you see the same above and below it's correct.
15+
</head>
16+
17+
<body>
18+
<h1>Scheduler Fixture</h1>
19+
<p>
20+
This fixture is for manual testing purposes, and the patterns used in
21+
implementing it should not be used as a model. This is mainly for anyone
22+
working on making changes to the `schedule` module.
23+
</p>
24+
<h2>Tests:</h2>
25+
<ol>
26+
<li>
27+
<button onClick="runTestOne()">Run Test 1</button>
28+
<p>Calls the callback within the frame when not blocked:</p>
29+
<div><b>Expected:</b></div>
30+
<div id="test-1-expected">
31+
</div>
32+
<div> -------------------------------------------------</div>
33+
<div> If you see the same above and below it's correct.
3234
<div> -------------------------------------------------</div>
3335
<div><b>Actual:</b></div>
3436
<div id="test-1"></div>
35-
</li>
36-
<li>
37-
<p>Accepts multiple callbacks and calls within frame when not blocked</p>
38-
<button onClick="runTestTwo()">Run Test 2</button>
39-
<div><b>Expected:</b></div>
40-
<div id="test-2-expected">
41-
</div>
42-
<div> -------------------------------------------------</div>
43-
<div> If you see the same above and below it's correct.
37+
</li>
38+
<li>
39+
<p>Accepts multiple callbacks and calls within frame when not blocked</p>
40+
<button onClick="runTestTwo()">Run Test 2</button>
41+
<div><b>Expected:</b></div>
42+
<div id="test-2-expected">
43+
</div>
44+
<div> -------------------------------------------------</div>
45+
<div> If you see the same above and below it's correct.
4446
<div> -------------------------------------------------</div>
4547
<div><b>Actual:</b></div>
4648
<div id="test-2"></div>
47-
</li>
48-
<li>
49-
<p>Schedules callbacks in correct order when they use scheduleWork to schedule themselves</p>
50-
<button onClick="runTestThree()">Run Test 3</button>
51-
<div><b>Expected:</b></div>
52-
<div id="test-3-expected">
53-
</div>
54-
<div> -------------------------------------------------</div>
55-
<div> If you see the same above and below it's correct.
49+
</li>
50+
<li>
51+
<p>Schedules callbacks in correct order when they use scheduleWork to schedule themselves</p>
52+
<button onClick="runTestThree()">Run Test 3</button>
53+
<div><b>Expected:</b></div>
54+
<div id="test-3-expected">
55+
</div>
56+
<div> -------------------------------------------------</div>
57+
<div> If you see the same above and below it's correct.
5658
<div> -------------------------------------------------</div>
5759
<div><b>Actual:</b></div>
5860
<div id="test-3"></div>
59-
</li>
60-
<li>
61-
<p>Calls timed out callbacks and then any more pending callbacks, defers others if time runs out</p>
62-
<button onClick="runTestFour()">Run Test 4</button>
63-
<div><b>Expected:</b></div>
64-
<div id="test-4-expected">
65-
</div>
66-
<div> -------------------------------------------------</div>
67-
<div> If you see the same above and below it's correct.
61+
</li>
62+
<li>
63+
<p>Calls timed out callbacks and then any more pending callbacks, defers others if time runs out</p>
64+
<button onClick="runTestFour()">Run Test 4</button>
65+
<div><b>Expected:</b></div>
66+
<div id="test-4-expected">
67+
</div>
68+
<div> -------------------------------------------------</div>
69+
<div> If you see the same above and below it's correct.
6870
<div> -------------------------------------------------</div>
6971
<div><b>Actual:</b></div>
7072
<div id="test-4"></div>
71-
</li>
72-
<li>
73-
<p>When some callbacks throw errors, still calls them all within the same frame</p>
74-
<p><b>IMPORTANT:</b> Open the console when you run this! Inspect the logs there!</p>
75-
<button onClick="runTestFive()">Run Test 5</button>
76-
</li>
77-
<li>
78-
<p>When some callbacks throw errors <b> and some also time out</b>, still calls them all within the same frame</p>
79-
<p><b>IMPORTANT:</b> Open the console when you run this! Inspect the logs there!</p>
80-
<button onClick="runTestSix()">Run Test 6</button>
81-
</li>
82-
<li>
83-
<p>Continues calling callbacks even when user switches away from this tab</p>
84-
<button onClick="runTestSeven()">Run Test 7</button>
85-
<div><b>Click the button above, observe the counter, then switch to
86-
another tab and switch back:</b></div>
87-
<div id="test-7">
88-
</div>
89-
<div> If the counter advanced while you were away from this tab, it's correct.</div>
90-
</li>
91-
</ol>
92-
<script src="../../build/dist/react.development.js"></script>
93-
<script src="../../build/node_modules/scheduler/umd/scheduler.development.js"></script>
94-
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
95-
<script type="text/babel">
73+
</li>
74+
<li>
75+
<p>When some callbacks throw errors, still calls them all within the same frame</p>
76+
<p><b>IMPORTANT:</b> Open the console when you run this! Inspect the logs there!</p>
77+
<button onClick="runTestFive()">Run Test 5</button>
78+
</li>
79+
<li>
80+
<p>When some callbacks throw errors <b> and some also time out</b>, still calls them all within the same frame</p>
81+
<p><b>IMPORTANT:</b> Open the console when you run this! Inspect the logs there!</p>
82+
<button onClick="runTestSix()">Run Test 6</button>
83+
</li>
84+
<li>
85+
<p>Continues calling callbacks even when user switches away from this tab</p>
86+
<button onClick="runTestSeven()">Run Test 7</button>
87+
<div><b>Click the button above, observe the counter, then switch to
88+
another tab and switch back:</b></div>
89+
<div id="test-7">
90+
</div>
91+
<div> If the counter advanced while you were away from this tab, it's correct.</div>
92+
</li>
93+
</ol>
94+
<script src="../../build/dist/react.development.js"></script>
95+
<script src="../../build/node_modules/scheduler/umd/scheduler.development.js"></script>
96+
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
97+
<script type="text/babel">
9698
const {
97-
unstable_scheduleWork: scheduleWork,
98-
unstable_cancelWork: cancelWork,
99+
unstable_scheduleCallback: scheduleCallback,
100+
unstable_cancelCallback: cancelCallback,
99101
unstable_now: now
100102
} = Scheduler;
101103
function displayTestResult(testNumber) {
@@ -496,4 +498,4 @@ <h2>Tests:</h2>
496498
}
497499
</script type="text/babel">
498500
</body>
499-
</html>
501+
</html>

fixtures/tracing/script.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ function checkSchedulerAPI() {
3030
if (
3131
typeof Scheduler === 'undefined' ||
3232
typeof Scheduler.unstable_now !== 'function' ||
33-
typeof Scheduler.unstable_scheduleWork !== 'function' ||
34-
typeof Scheduler.unstable_cancelScheduledWork !== 'function'
33+
typeof Scheduler.unstable_scheduleCallback !== 'function' ||
34+
typeof Scheduler.unstable_cancelCallback !== 'function'
3535
) {
3636
throw 'API is not defined';
3737
}

fixtures/unstable-async/suspense/src/components/App.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {Placeholder, PureComponent} from 'react';
2-
import {unstable_scheduleWork} from 'scheduler';
2+
import {unstable_scheduleCallback} from 'scheduler';
33
import {
44
unstable_trace as trace,
55
unstable_wrap as wrap,
@@ -38,7 +38,7 @@ export default class App extends PureComponent {
3838
currentId: id,
3939
})
4040
);
41-
unstable_scheduleWork(
41+
unstable_scheduleCallback(
4242
wrap(() =>
4343
trace(`View ${id} (low-pri)`, performance.now(), () =>
4444
this.setState({

fixtures/unstable-async/time-slicing/src/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, {PureComponent} from 'react';
22
import {flushSync, render} from 'react-dom';
3-
import {unstable_scheduleWork} from 'scheduler';
3+
import {unstable_scheduleCallback} from 'scheduler';
44
import _ from 'lodash';
55
import Charts from './Charts';
66
import Clock from './Clock';
@@ -67,7 +67,7 @@ class App extends PureComponent {
6767
}
6868
this._ignoreClick = true;
6969

70-
unstable_scheduleWork(() => {
70+
unstable_scheduleCallback(() => {
7171
this.setState({showDemo: true}, () => {
7272
this._ignoreClick = false;
7373
});
@@ -107,7 +107,7 @@ class App extends PureComponent {
107107
this.debouncedHandleChange(value);
108108
break;
109109
case 'async':
110-
unstable_scheduleWork(() => {
110+
unstable_scheduleCallback(() => {
111111
this.setState({value});
112112
});
113113
break;

packages/react-art/src/ReactARTHostConfig.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
export {
99
unstable_now as now,
10-
unstable_scheduleWork as scheduleDeferredCallback,
11-
unstable_cancelScheduledWork as cancelDeferredCallback,
10+
unstable_scheduleCallback as scheduleDeferredCallback,
11+
unstable_cancelCallback as cancelDeferredCallback,
1212
} from 'scheduler';
1313
import Transform from 'art/core/transform';
1414
import Mode from 'art/modes/current';
@@ -42,7 +42,7 @@ function addEventListeners(instance, type, listener) {
4242
instance._subscriptions[type] = instance.subscribe(
4343
type,
4444
createEventHandler(instance),
45-
instance,
45+
instance
4646
);
4747
}
4848
} else {
@@ -199,7 +199,7 @@ function applyRenderableNodeProps(instance, props, prevProps = {}) {
199199
props.strokeWidth,
200200
props.strokeCap,
201201
props.strokeJoin,
202-
props.strokeDash,
202+
props.strokeDash
203203
);
204204
}
205205
}
@@ -276,7 +276,7 @@ export function createInstance(type, props, internalInstanceHandle) {
276276
props.children,
277277
props.font,
278278
props.alignment,
279-
props.path,
279+
props.path
280280
);
281281
instance._applyProps = applyTextProps;
282282
break;
@@ -292,7 +292,7 @@ export function createInstance(type, props, internalInstanceHandle) {
292292
export function createTextInstance(
293293
text,
294294
rootContainerInstance,
295-
internalInstanceHandle,
295+
internalInstanceHandle
296296
) {
297297
return text;
298298
}
@@ -365,15 +365,15 @@ export function appendChildToContainer(parentInstance, child) {
365365
export function insertBefore(parentInstance, child, beforeChild) {
366366
invariant(
367367
child !== beforeChild,
368-
'ReactART: Can not insert node before itself',
368+
'ReactART: Can not insert node before itself'
369369
);
370370
child.injectBefore(beforeChild);
371371
}
372372

373373
export function insertInContainerBefore(parentInstance, child, beforeChild) {
374374
invariant(
375375
child !== beforeChild,
376-
'ReactART: Can not insert node before itself',
376+
'ReactART: Can not insert node before itself'
377377
);
378378
child.injectBefore(beforeChild);
379379
}
@@ -401,7 +401,7 @@ export function commitUpdate(
401401
updatePayload,
402402
type,
403403
oldProps,
404-
newProps,
404+
newProps
405405
) {
406406
instance._applyProps(instance, newProps, oldProps);
407407
}

0 commit comments

Comments
 (0)