(request: Request, task: ReplayTask)
| 5322 | } |
| 5323 | |
| 5324 | function retryReplayTask(request: Request, task: ReplayTask): void { |
| 5325 | if (task.replay.pendingTasks === 0) { |
| 5326 | // There are no pending tasks working on this set, so we must have aborted. |
| 5327 | return; |
| 5328 | } |
| 5329 | |
| 5330 | // We restore the context to what it was when we suspended. |
| 5331 | // We don't restore it after we leave because it's likely that we'll end up |
| 5332 | // needing a very similar context soon again. |
| 5333 | switchContext(task.context); |
| 5334 | let prevTaskInDEV = null; |
| 5335 | if (__DEV__) { |
| 5336 | prevTaskInDEV = currentTaskInDEV; |
| 5337 | setCurrentTaskInDEV(task); |
| 5338 | } |
| 5339 | |
| 5340 | try { |
| 5341 | // We call the destructive form that mutates this task. That way if something |
| 5342 | // suspends again, we can reuse the same task instead of spawning a new one. |
| 5343 | if (typeof task.replay.slots === 'number') { |
| 5344 | const resumeSegmentID = task.replay.slots; |
| 5345 | resumeNode(request, task, resumeSegmentID, task.node, task.childIndex); |
| 5346 | } else { |
| 5347 | retryNode(request, task); |
| 5348 | } |
| 5349 | |
| 5350 | if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) { |
| 5351 | throw new Error( |
| 5352 | "Couldn't find all resumable slots by key/index during replaying. " + |
| 5353 | "The tree doesn't match so React will fallback to client rendering.", |
| 5354 | ); |
| 5355 | } |
| 5356 | task.replay.pendingTasks--; |
| 5357 | |
| 5358 | task.abortSet.delete(task); |
| 5359 | finishedTask(request, task.blockedBoundary, task.row, null); |
| 5360 | } catch (thrownValue) { |
| 5361 | resetHooksState(); |
| 5362 | |
| 5363 | const x = |
| 5364 | thrownValue === SuspenseException |
| 5365 | ? // This is a special type of exception used for Suspense. For historical |
| 5366 | // reasons, the rest of the Suspense implementation expects the thrown |
| 5367 | // value to be a thenable, because before `use` existed that was the |
| 5368 | // (unstable) API for suspending. This implementation detail can change |
| 5369 | // later, once we deprecate the old API in favor of `use`. |
| 5370 | getSuspendedThenable() |
| 5371 | : thrownValue; |
| 5372 | |
| 5373 | if (typeof x === 'object' && x !== null) { |
| 5374 | // $FlowFixMe[method-unbinding] |
| 5375 | if (typeof x.then === 'function') { |
| 5376 | // Something suspended again, let's pick it back up later. |
| 5377 | const ping = task.ping; |
| 5378 | x.then(ping, ping); |
| 5379 | task.thenableState = |
| 5380 | thrownValue === SuspenseException |
| 5381 | ? getThenableStateAfterSuspending() |
no test coverage detected