@@ -39,6 +39,7 @@ export {
39
39
40
40
// Capture local references to native APIs, in case a polyfill overrides them.
41
41
const perf = window . performance ;
42
+ const setTimeout = window . setTimeout ;
42
43
43
44
// Use experimental Chrome Scheduler postTask API.
44
45
const scheduler = global . scheduler ;
@@ -112,7 +113,7 @@ export function unstable_scheduleCallback<T>(
112
113
runTask . bind ( null , priorityLevel , postTaskPriority , node , callback ) ,
113
114
postTaskOptions ,
114
115
)
115
- . catch ( handlePostTaskError ) ;
116
+ . catch ( handleAbortError ) ;
116
117
117
118
return node ;
118
119
}
@@ -124,56 +125,49 @@ function runTask<T>(
124
125
callback: SchedulerCallback< T > ,
125
126
) {
126
127
deadline = getCurrentTime ( ) + yieldInterval ;
128
+ let result ;
127
129
try {
128
130
currentPriorityLevel_DEPRECATED = priorityLevel ;
129
131
const didTimeout_DEPRECATED = false ;
130
- const result = callback ( didTimeout_DEPRECATED ) ;
131
- if ( typeof result === 'function' ) {
132
- // Assume this is a continuation
133
- const continuation : SchedulerCallback < T > = (result: any);
134
- const continuationController = new TaskController();
135
- const continuationOptions = {
136
- priority : postTaskPriority ,
137
- signal : continuationController . signal ,
138
- } ;
139
- // Update the original callback node's controller, since even though we're
140
- // posting a new task, conceptually it's the same one.
141
- node._controller = continuationController;
142
- scheduler
143
- .postTask(
144
- runTask.bind(
145
- null,
146
- priorityLevel,
147
- postTaskPriority,
148
- node,
149
- continuation,
150
- ),
151
- continuationOptions,
152
- )
153
- .catch(handlePostTaskError);
154
- }
132
+ result = callback ( didTimeout_DEPRECATED ) ;
133
+ } catch ( error ) {
134
+ // We're inside a promise. If we don't handle this error, then it will
135
+ // trigger an "Unhandled promise rejection" error. We don't want that, but
136
+ // we do want the default error reporting behavior that normal (non-Promise)
137
+ // tasks get for unhandled errors.
138
+ //
139
+ // So we'll re-throw the error inside a regular browser task.
140
+ setTimeout ( ( ) => {
141
+ throw error ;
142
+ } ) ;
155
143
} finally {
156
144
currentPriorityLevel_DEPRECATED = NormalPriority ;
157
145
}
146
+ if ( typeof result === 'function' ) {
147
+ // Assume this is a continuation
148
+ const continuation : SchedulerCallback < T > = (result: any);
149
+ const continuationController = new TaskController();
150
+ const continuationOptions = {
151
+ priority : postTaskPriority ,
152
+ signal : continuationController . signal ,
153
+ } ;
154
+ // Update the original callback node's controller, since even though we're
155
+ // posting a new task, conceptually it's the same one.
156
+ node._controller = continuationController;
157
+ scheduler
158
+ .postTask(
159
+ runTask.bind(null, priorityLevel, postTaskPriority, node, continuation),
160
+ continuationOptions,
161
+ )
162
+ .catch(handleAbortError);
163
+ }
158
164
}
159
165
160
- function handlePostTaskError ( error ) {
161
- // This error is either a user error thrown by a callback, or an AbortError
162
- // as a result of a cancellation.
163
- //
164
- // User errors trigger a global `error` event even if we don't rethrow them.
165
- // In fact, if we do rethrow them, they'll get reported to the console twice.
166
- // I'm not entirely sure the current `postTask` spec makes sense here. If I
167
- // catch a `postTask` call, it shouldn't trigger a global error.
168
- //
166
+ function handleAbortError ( error ) {
169
167
// Abort errors are an implementation detail. We don't expose the
170
168
// TaskController to the user, nor do we expose the promise that is returned
171
- // from `postTask`. So we shouldn't rethrow those, either, since there's no
172
- // way to handle them. (If we did return the promise to the user, then it
173
- // should be up to them to handle the AbortError.)
174
- //
175
- // In either case, we can suppress the error, barring changes to the spec
176
- // or the Scheduler API.
169
+ // from `postTask`. So we should suppress them, since there's no way for the
170
+ // user to handle them.
177
171
}
178
172
179
173
export function unstable_cancelCallback(node: CallbackNode) {
0 commit comments