@@ -12,6 +12,8 @@ import type {ExpirationTime} from './ReactFiberExpirationTime';
12
12
13
13
import { NoWork } from './ReactFiberExpirationTime' ;
14
14
15
+ import { enableSuspense } from 'shared/ReactFeatureFlags' ;
16
+
15
17
// Because we don't have a global queue of updates, we use this module to keep
16
18
// track of the pending levels of work that have yet to be flushed. You can
17
19
// think of a PendingWork object as representing a batch of work that will
@@ -31,11 +33,13 @@ export type PendingWork = {
31
33
} ;
32
34
33
35
function insertPendingWorkAtPosition ( root , work , insertAfter , insertBefore ) {
34
- work . next = insertBefore ;
35
- if ( insertAfter === null ) {
36
- root . firstPendingWork = work ;
37
- } else {
38
- insertAfter . next = work ;
36
+ if ( enableSuspense ) {
37
+ work . next = insertBefore ;
38
+ if ( insertAfter === null ) {
39
+ root . firstPendingWork = work ;
40
+ } else {
41
+ insertAfter . next = work ;
42
+ }
39
43
}
40
44
}
41
45
@@ -44,39 +48,41 @@ export function addPendingWork(
44
48
startTime : ExpirationTime ,
45
49
expirationTime : ExpirationTime ,
46
50
) : void {
47
- let match = null ;
48
- let insertAfter = null ;
49
- let insertBefore = root . firstPendingWork ;
50
- while ( insertBefore !== null ) {
51
- if ( insertBefore . expirationTime >= expirationTime ) {
52
- // Retry anything with an equal or lower expiration time, since it may
53
- // be unblocked by the new work.
54
- insertBefore . shouldTryResuming = true ;
55
- }
56
- if ( insertBefore . expirationTime === expirationTime ) {
57
- // Found a matching bucket. But we'll keep iterating so we can set
58
- // `shouldTryResuming` as needed.
59
- match = insertBefore ;
60
- // Update the start time. We always measure from the most recently
61
- // added update.
62
- match . startTime = startTime ;
51
+ if ( enableSuspense ) {
52
+ let match = null ;
53
+ let insertAfter = null ;
54
+ let insertBefore = root . firstPendingWork ;
55
+ while ( insertBefore !== null ) {
56
+ if ( insertBefore . expirationTime >= expirationTime ) {
57
+ // Retry anything with an equal or lower expiration time, since it may
58
+ // be unblocked by the new work.
59
+ insertBefore . shouldTryResuming = true ;
60
+ }
61
+ if ( insertBefore . expirationTime === expirationTime ) {
62
+ // Found a matching bucket. But we'll keep iterating so we can set
63
+ // `shouldTryResuming` as needed.
64
+ match = insertBefore ;
65
+ // Update the start time. We always measure from the most recently
66
+ // added update.
67
+ match . startTime = startTime ;
68
+ }
69
+ if ( match === null && insertBefore . expirationTime > expirationTime ) {
70
+ // Found the insertion position
71
+ break ;
72
+ }
73
+ insertAfter = insertBefore ;
74
+ insertBefore = insertBefore . next ;
63
75
}
64
- if ( match === null && insertBefore . expirationTime > expirationTime ) {
65
- // Found the insertion position
66
- break ;
76
+ if ( match === null ) {
77
+ const work : PendingWork = {
78
+ startTime,
79
+ expirationTime,
80
+ isSuspended : false ,
81
+ shouldTryResuming : false ,
82
+ next : null ,
83
+ } ;
84
+ insertPendingWorkAtPosition ( root , work , insertAfter , insertBefore ) ;
67
85
}
68
- insertAfter = insertBefore ;
69
- insertBefore = insertBefore . next ;
70
- }
71
- if ( match === null ) {
72
- const work : PendingWork = {
73
- startTime,
74
- expirationTime,
75
- isSuspended : false ,
76
- shouldTryResuming : false ,
77
- next : null ,
78
- } ;
79
- insertPendingWorkAtPosition ( root , work , insertAfter , insertBefore ) ;
80
86
}
81
87
}
82
88
@@ -85,112 +91,126 @@ export function flushPendingWork(
85
91
currentTime : ExpirationTime ,
86
92
remainingExpirationTime : ExpirationTime ,
87
93
) {
88
- // Pop all work that has higher priority than the remaining priority.
89
- let firstUnflushedWork = root . firstPendingWork ;
90
- while ( firstUnflushedWork !== null ) {
91
- if (
92
- remainingExpirationTime !== NoWork &&
93
- firstUnflushedWork . expirationTime >= remainingExpirationTime
94
- ) {
95
- break ;
94
+ if ( enableSuspense ) {
95
+ // Pop all work that has higher priority than the remaining priority.
96
+ let firstUnflushedWork = root . firstPendingWork ;
97
+ while ( firstUnflushedWork !== null ) {
98
+ if (
99
+ remainingExpirationTime !== NoWork &&
100
+ firstUnflushedWork . expirationTime >= remainingExpirationTime
101
+ ) {
102
+ break ;
103
+ }
104
+ firstUnflushedWork = firstUnflushedWork . next ;
96
105
}
97
- firstUnflushedWork = firstUnflushedWork . next ;
98
- }
99
- root . firstPendingWork = firstUnflushedWork ;
106
+ root . firstPendingWork = firstUnflushedWork ;
100
107
101
- if ( firstUnflushedWork === null ) {
102
- if ( remainingExpirationTime !== NoWork ) {
108
+ if ( firstUnflushedWork === null ) {
109
+ if ( remainingExpirationTime !== NoWork ) {
110
+ // There was an update during the render phase that wasn't flushed.
111
+ addPendingWork ( root , currentTime , remainingExpirationTime ) ;
112
+ }
113
+ } else if (
114
+ remainingExpirationTime !== NoWork &&
115
+ firstUnflushedWork . expirationTime > remainingExpirationTime
116
+ ) {
103
117
// There was an update during the render phase that wasn't flushed.
104
118
addPendingWork ( root , currentTime , remainingExpirationTime ) ;
105
119
}
106
- } else if (
107
- remainingExpirationTime !== NoWork &&
108
- firstUnflushedWork . expirationTime > remainingExpirationTime
109
- ) {
110
- // There was an update during the render phase that wasn't flushed.
111
- addPendingWork ( root , currentTime , remainingExpirationTime ) ;
112
120
}
113
121
}
114
122
115
123
export function suspendPendingWork (
116
124
root : FiberRoot ,
117
125
expirationTime : ExpirationTime ,
118
126
) : void {
119
- let work = root . firstPendingWork ;
120
- while ( work !== null ) {
121
- if ( work . expirationTime === expirationTime ) {
122
- work . isSuspended = true ;
123
- work . shouldTryResuming = false ;
124
- return ;
125
- }
126
- if ( work . expirationTime > expirationTime ) {
127
- return ;
127
+ if ( enableSuspense ) {
128
+ let work = root . firstPendingWork ;
129
+ while ( work !== null ) {
130
+ if ( work . expirationTime === expirationTime ) {
131
+ work . isSuspended = true ;
132
+ work . shouldTryResuming = false ;
133
+ return ;
134
+ }
135
+ if ( work . expirationTime > expirationTime ) {
136
+ return ;
137
+ }
138
+ work = work . next ;
128
139
}
129
- work = work . next ;
130
140
}
131
141
}
132
142
133
143
export function resumePendingWork (
134
144
root : FiberRoot ,
135
145
expirationTime : ExpirationTime ,
136
146
) : void {
137
- // Called when a promise resolves. This "pings" React to retry the previously
138
- // suspended render.
139
- let work = root . firstPendingWork ;
140
- while ( work !== null ) {
141
- if ( work . expirationTime === expirationTime ) {
142
- work . shouldTryResuming = true ;
143
- }
144
- if ( work . expirationTime > expirationTime ) {
145
- return ;
147
+ if ( enableSuspense ) {
148
+ // Called when a promise resolves. This "pings" React to retry the previously
149
+ // suspended render.
150
+ let work = root . firstPendingWork ;
151
+ while ( work !== null ) {
152
+ if ( work . expirationTime === expirationTime ) {
153
+ work . shouldTryResuming = true ;
154
+ }
155
+ if ( work . expirationTime > expirationTime ) {
156
+ return ;
157
+ }
158
+ work = work . next ;
146
159
}
147
- work = work . next ;
148
160
}
149
161
}
150
162
151
163
export function findNextExpirationTimeToWorkOn (
152
164
root : FiberRoot ,
153
165
) : ExpirationTime {
154
- // Return the earliest time that either isn't suspended or has been pinged.
155
- let lastSuspendedTime = NoWork ;
156
- let lastRetryTime = NoWork ;
157
- let work = root . firstPendingWork ;
158
- while ( work !== null ) {
159
- if ( ! work . isSuspended ) {
160
- return work . expirationTime ;
161
- }
162
- if (
163
- lastSuspendedTime === NoWork ||
164
- lastSuspendedTime < work . expirationTime
165
- ) {
166
- lastSuspendedTime = work . expirationTime ;
167
- }
168
- if ( work . shouldTryResuming ) {
169
- if ( lastRetryTime === NoWork || lastRetryTime < work . expirationTime ) {
170
- lastRetryTime = work . expirationTime ;
166
+ if ( enableSuspense ) {
167
+ // Return the earliest time that either isn't suspended or has been pinged.
168
+ let lastSuspendedTime = NoWork ;
169
+ let lastRetryTime = NoWork ;
170
+ let work = root . firstPendingWork ;
171
+ while ( work !== null ) {
172
+ if ( ! work . isSuspended ) {
173
+ return work . expirationTime ;
171
174
}
175
+ if (
176
+ lastSuspendedTime === NoWork ||
177
+ lastSuspendedTime < work . expirationTime
178
+ ) {
179
+ lastSuspendedTime = work . expirationTime ;
180
+ }
181
+ if ( work . shouldTryResuming ) {
182
+ if ( lastRetryTime === NoWork || lastRetryTime < work . expirationTime ) {
183
+ lastRetryTime = work . expirationTime ;
184
+ }
185
+ }
186
+ work = work . next ;
172
187
}
173
- work = work . next ;
174
- }
175
- // This has the effect of coalescing all async updates that occur while we're
176
- // in a suspended state. This prevents us from rendering an intermediate state
177
- // that is no longer valid. An example is a tab switching interface: if
178
- // switching to a new tab is suspended, we should only switch to the last
179
- // tab that was clicked. If the user switches to tab A and then tab B, we
180
- // should continue suspending until B is ready.
181
- if ( lastRetryTime >= lastSuspendedTime ) {
182
- return lastRetryTime ;
188
+ // This has the effect of coalescing all async updates that occur while we're
189
+ // in a suspended state. This prevents us from rendering an intermediate state
190
+ // that is no longer valid. An example is a tab switching interface: if
191
+ // switching to a new tab is suspended, we should only switch to the last
192
+ // tab that was clicked. If the user switches to tab A and then tab B, we
193
+ // should continue suspending until B is ready.
194
+ if ( lastRetryTime >= lastSuspendedTime ) {
195
+ return lastRetryTime ;
196
+ }
197
+ return NoWork ;
198
+ } else {
199
+ return root . current . expirationTime ;
183
200
}
184
- return NoWork ;
185
201
}
186
202
187
203
export function findStartTime ( root : FiberRoot , expirationTime : ExpirationTime ) {
188
- let match = root . firstPendingWork ;
189
- while ( match !== null ) {
190
- if ( match . expirationTime === expirationTime ) {
191
- return match . startTime ;
204
+ if ( enableSuspense ) {
205
+ let match = root . firstPendingWork ;
206
+ while ( match !== null ) {
207
+ if ( match . expirationTime === expirationTime ) {
208
+ return match . startTime ;
209
+ }
210
+ match = match . next ;
192
211
}
193
- match = match . next ;
212
+ return NoWork ;
213
+ } else {
214
+ return NoWork ;
194
215
}
195
- return NoWork ;
196
216
}
0 commit comments