Remove confusing for-loop in favor of a helper function
This logic is hopefully easier to follow. Added more inline comments to explain how the algorithm works.
Andrew Clark committed
Dec 15, 2016 at 18:15 UTC
f070aaa1b84a239a0ed8aeb98ebc185ae925b6f3
1 file changed
+49
-44
src/renderers/shared/fiber/ReactFiberUpdateQueue.js
+49
-44
@@ -162,6 +162,26 @@ function insertUpdateIntoQueue(queue, update, insertAfter, insertBefore) {
162
}
163
}
164
165
+// Returns the update after which the incoming update should be inserted into
166
+// the queue, or null if it should be inserted at beginning.
167
+function findInsertionPosition(queue, update) : Update | null {
168
+ const priorityLevel = update.priorityLevel;
169
+ let insertAfter = null;
170
+ let insertBefore = null;
171
+ if (queue.last && comparePriority(queue.last.priorityLevel, priorityLevel) <= 0) {
172
+ // Fast path for the common case where the update should be inserted at
173
+ // the end of the queue.
174
+ insertAfter = queue.last;
175
+ } else {
176
+ insertBefore = queue.first;
177
+ while (insertBefore && comparePriority(insertBefore.priorityLevel, priorityLevel) <= 0) {
178
+ insertAfter = insertBefore;
179
+ insertBefore = insertBefore.next;
180
+ }
181
+ }
182
+ return insertAfter;
183
+}
184
+
185
// The work-in-progress queue is a subset of the current queue (if it exists).
186
// We need to insert the incoming update into both lists. However, it's possible
187
// that the correct position in one list will be different from the position in
@@ -189,7 +209,6 @@ function insertUpdateIntoQueue(queue, update, insertAfter, insertBefore) {
209
//
210
// However, if incoming update is inserted into the same position of both lists,
211
// we shouldn't make a copy.
192
-
212
function insertUpdate(fiber : Fiber, update : Update, methodName : ?string) : void {
213
const queue1 = ensureUpdateQueue(fiber);
214
const queue2 = fiber.alternate ? ensureUpdateQueue(fiber.alternate) : null;
@@ -218,54 +237,40 @@ function insertUpdate(fiber : Fiber, update : Update, methodName : ?string) : vo
237
}
238
}
239
221
- const priorityLevel = update.priorityLevel;
240
+ // Find the insertion position in the first queue.
241
+ const insertAfter1 = findInsertionPosition(queue1, update);
242
+ const insertBefore1 = insertAfter1 ? insertAfter1.next : queue1.first;
243
223
- let queue = queue1;
224
- let insertAfter1;
225
- let insertBefore1;
226
- let insertAfter2;
227
- let insertBefore2;
228
- for (let i = 0; queue && i < 2; i++) {
229
- let insertAfter = null;
230
- let insertBefore = null;
231
- if (queue.last && comparePriority(queue.last.priorityLevel, priorityLevel) <= 0) {
232
- // Fast path for the common case where the update should be inserted at
233
- // the end of the queue.
234
- insertAfter = queue.last;
235
- } else {
236
- insertBefore = queue.first;
237
- while (insertBefore && comparePriority(insertBefore.priorityLevel, priorityLevel) <= 0) {
238
- insertAfter = insertBefore;
239
- insertBefore = insertBefore.next;
240
- }
241
- }
242
- if (i === 0) {
243
- insertAfter1 = insertAfter;
244
- insertBefore1 = insertBefore;
245
- queue = queue2;
246
- } else {
247
- insertAfter2 = insertAfter;
248
- insertBefore2 = insertBefore;
249
- queue = null;
250
- }
244
+ if (!queue2) {
245
+ // If there's no alternate queue, there's nothing else to do but insert.
246
+ insertUpdateIntoQueue(queue1, update, insertAfter1, insertBefore1);
247
+ return;
248
}
249
253
- const update1 = update;
254
- insertUpdateIntoQueue(queue1, update1, insertAfter1, insertBefore1);
250
+ // If there is an alternate queue, find the insertion position.
251
+ const insertAfter2 = findInsertionPosition(queue2, update);
252
+ const insertBefore2 = insertAfter2 ? insertAfter2.next : queue2.first;
253
256
- if (queue2) {
257
- let update2;
258
- if (insertBefore1 === insertBefore2) {
259
- // The update is inserted into the same position of both lists. There's no
260
- // need to clone the update.
261
- update2 = update1;
262
- } else {
263
- // The update is inserted into two separate positions. Make a clone of the
264
- // update and insert it twice. One or the other will be dropped the next
265
- // time we commit.
266
- update2 = cloneUpdate(update1);
267
- }
254
+ // Now we can insert into the first queue. This must come after finding both
255
+ // insertion positions because it mutates the list.
256
+ insertUpdateIntoQueue(queue1, update, insertAfter1, insertBefore1);
257
+
258
+ if (insertBefore1 !== insertBefore2) {
259
+ // The insertion positions are different, so we need to clone the update and
260
+ // insert the clone into the alternate queue.
261
+ const update2 = cloneUpdate(update);
262
insertUpdateIntoQueue(queue2, update2, insertAfter2, insertBefore2);
263
+ } else {
264
+ // The insertion positions are the same, so when we inserted into the first
265
+ // queue, it also inserted into the alternate. All we need to do is update
266
+ // the alternate queue's `first` and `last` pointers, in case they
267
+ // have changed.
268
+ if (!insertAfter2) {
269
+ queue2.first = update;
270
+ }
271
+ if (!insertBefore2) {
272
+ queue2.last = null;
273
+ }
274
}
275
}
276