@samitouri / QOS-React / commits / 49f0c952b5

Drop childInProgress

I will try a slightly different but similar strategy.

Sebastian Markbage committed Sep 1, 2016 at 20:50 UTC 49f0c952b5f796500fb25188e89be4099b0b740e
2 files changed +47 -89
src/renderers/shared/fiber/ReactFiber.js
-9
@@ -89,7 +89,6 @@ export type Fiber = Instance & {
89 firstEffect: ?Fiber,
90 lastEffect: ?Fiber,
91
92 -
92 // This will be used to quickly determine if a subtree has no pending changes.
93 pendingWorkPriority: PriorityLevel,
94
@@ -98,10 +97,6 @@ export type Fiber = Instance & {
97 // memory if we need to.
98 alternate: ?Fiber,
99
101 - // Keeps track of the children that are currently being processed but have not
102 - // yet completed.
103 - childInProgress: ?Fiber,
104 -
100 // Conceptual aliases
101 // workInProgress : Fiber -> alternate The alternate used for reuse happens
102 // to be the same as work in progress.
@@ -140,8 +135,6 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
135
136 pendingWorkPriority: NoWork,
137
143 - childInProgress: null,
144 -
138 alternate: null,
139
140 };
@@ -162,7 +155,6 @@ exports.cloneFiber = function(fiber : Fiber, priorityLevel : PriorityLevel) : Fi
155 if (alt) {
156 alt.stateNode = fiber.stateNode;
157 alt.child = fiber.child;
165 - alt.childInProgress = fiber.childInProgress;
158 alt.sibling = fiber.sibling;
159 alt.ref = fiber.ref;
160 alt.pendingProps = fiber.pendingProps;
@@ -185,7 +177,6 @@ exports.cloneFiber = function(fiber : Fiber, priorityLevel : PriorityLevel) : Fi
177 alt.type = fiber.type;
178 alt.stateNode = fiber.stateNode;
179 alt.child = fiber.child;
188 - alt.childInProgress = fiber.childInProgress;
180 alt.sibling = fiber.sibling;
181 alt.ref = fiber.ref;
182 // pendingProps is here for symmetry but is unnecessary in practice for now.
src/renderers/shared/fiber/ReactFiberBeginWork.js
+47 -80
@@ -40,34 +40,28 @@ var {
40 module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
41
42 function reconcileChildren(current, workInProgress, nextChildren) {
43 - // TODO: Children needs to be able to reconcile in place if we are
44 - // overriding progressed work.
45 - const priority = workInProgress.pendingWorkPriority;
46 - reconcileChildrenAtPriority(current, workInProgress, nextChildren, priority);
47 - }
48 -
49 - function reconcileChildrenAtPriority(current, workInProgress, nextChildren, priorityLevel) {
50 - if (current && current.childInProgress) {
51 - workInProgress.childInProgress = reconcileChildFibersInPlace(
52 - workInProgress,
53 - current.childInProgress,
54 - nextChildren,
55 - priorityLevel
56 - );
57 - // This is now invalid because we reused nodes.
58 - current.childInProgress = null;
59 - } else if (workInProgress.childInProgress) {
60 - workInProgress.childInProgress = reconcileChildFibersInPlace(
43 + const priorityLevel = workInProgress.pendingWorkPriority;
44 + // At this point any memoization is no longer valid since we'll have changed
45 + // the children.
46 + workInProgress.memoizedProps = null;
47 + if (current && current.child === workInProgress.child) {
48 + // If the current child is the same as the work in progress, it means that
49 + // we haven't yet started any work on these children. Therefore, we use
50 + // the clone algorithm to create a copy of all the current children.
51 + workInProgress.child = reconcileChildFibers(
52 workInProgress,
62 - workInProgress.childInProgress,
53 + workInProgress.child,
54 nextChildren,
55 priorityLevel
56 );
57 } else {
67 - // TODO:
68 - workInProgress.childInProgress = reconcileChildFibers(
58 + // If, on the other hand, we don't have a current fiber or if it is
59 + // already using a clone, that means we've already begun some work on this
60 + // tree and we can continue where we left off by reconciling against the
61 + // existing children.
62 + workInProgress.child = reconcileChildFibersInPlace(
63 workInProgress,
70 - current ? current.child : workInProgress.child,
64 + workInProgress.child,
65 nextChildren,
66 priorityLevel
67 );
@@ -80,7 +74,7 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
74
75 var nextChildren = fn(props);
76 reconcileChildren(current, workInProgress, nextChildren);
83 - return workInProgress.childInProgress;
77 + return workInProgress.child;
78 }
79
80 function updateClassComponent(current : ?Fiber, workInProgress : Fiber) {
@@ -97,13 +91,13 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
91 return bailoutOnCurrent(current, workInProgress);
92 }
93 }
100 - if (!workInProgress.childInProgress && workInProgress.memoizedProps) {
94 + if (workInProgress.memoizedProps) {
95 // Reset the props, in case this is a ping-pong case rather than a
96 // completed update case. For the completed update case, the instance
97 // props will already be the memoizedProps.
98 instance.props = workInProgress.memoizedProps;
99 if (!instance.shouldComponentUpdate(props)) {
106 - return bailoutOnAlreadyFinishedWork(current, workInProgress);
100 + // return bailoutOnAlreadyFinishedWork(current, workInProgress);
101 }
102 }
103 }
@@ -112,44 +106,20 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
106 var nextChildren = instance.render();
107 reconcileChildren(current, workInProgress, nextChildren);
108
115 - return workInProgress.childInProgress;
109 + return workInProgress.child;
110 }
111
112 function updateHostComponent(current, workInProgress) {
119 - var nextChildren = workInProgress.pendingProps.children;
120 -
121 - let priority = workInProgress.pendingWorkPriority;
122 - if (workInProgress.pendingProps.hidden && priority !== OffscreenPriority) {
123 - // If this host component is hidden, we can reconcile its children at
124 - // the lowest priority and bail out from this particular pass. Unless, we're
125 - // currently reconciling the lowest priority.
126 - // If we have a child in progress already, we reconcile against that set
127 - // to retain any work within it. We'll recreate any component that was in
128 - // the current set and next set but not in the previous in progress set.
129 - // TODO: This attaches a node that hasn't completed rendering so it
130 - // becomes part of the render tree, even though it never completed. Its
131 - // `output` property is unpredictable because of it.
132 - reconcileChildrenAtPriority(current, workInProgress, nextChildren, OffscreenPriority);
133 - workInProgress.child = current ? current.child : null;
134 - let child = workInProgress.childInProgress;
135 - while (child) {
136 - const currentChild = child.alternate;
137 - if (currentChild) {
138 - child.child = currentChild.child;
139 - child.childInProgress = currentChild.childInProgress;
140 - child.memoizedProps = currentChild.memoizedProps;
141 - child.output = currentChild.output;
142 - }
143 - child.nextEffect = null;
144 - child.firstEffect = null;
145 - child.lastEffect = null;
146 -
147 - child = child.sibling;
148 - }
149 - return null;
113 + if (workInProgress.pendingProps.hidden &&
114 + workInProgress.pendingWorkPriority !== OffscreenPriority) {
115 + // If this host component is hidden, we can bail out and ignore this.
116 + // We'll rerender it later at the lower priority.
117 + workInProgress.pendingWorkPriority = OffscreenPriority;
118 + return bailoutOnLowPriority(current, workInProgress);
119 } else {
120 + var nextChildren = workInProgress.pendingProps.children;
121 reconcileChildren(current, workInProgress, nextChildren);
152 - return workInProgress.childInProgress;
122 + return workInProgress.child;
123 }
124 }
125
@@ -172,7 +142,7 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
142 }
143 }
144 reconcileChildren(current, workInProgress, value);
175 - return workInProgress.childInProgress;
145 + return workInProgress.child;
146 }
147
148 function updateCoroutineComponent(current, workInProgress) {
@@ -240,7 +210,6 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
210 workInProgress.firstEffect = null;
211 workInProgress.lastEffect = null;
212
243 - workInProgress.childInProgress = null; // current.childInProgress;
213 workInProgress.child = current.child;
214
215 cloneChildFibers(workInProgress);
@@ -263,9 +232,6 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
232 workInProgress.lastEffect = null;
233
234 const child = workInProgress.child;
266 - if (workInProgress.childInProgress) {
267 - throw new Error('Child in progress means we cannot bail here.');
268 - }
235 if (child) {
236 // Ensure that the effects of reused work are preserved.
237 reuseChildrenEffects(workInProgress, child);
@@ -280,6 +246,15 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
246 return null;
247 }
248
249 + function bailoutOnLowPriority(current, workInProgress) {
250 + if (current) {
251 + workInProgress.child = current.child;
252 + workInProgress.memoizedProps = current.memoizedProps;
253 + workInProgress.output = current.output;
254 + }
255 + return null;
256 + }
257 +
258 function beginWork(current : ?Fiber, workInProgress : Fiber, priorityLevel) : ?Fiber {
259 if (!workInProgress.pendingProps) {
260 throw new Error('should have pending props here');
@@ -287,15 +262,7 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
262
263 if (workInProgress.pendingWorkPriority === NoWork ||
264 workInProgress.pendingWorkPriority > priorityLevel) {
290 -
291 - if (current) {
292 - workInProgress.child = current.child;
293 - workInProgress.childInProgress = current.childInProgress;
294 - workInProgress.memoizedProps = current.memoizedProps;
295 - workInProgress.output = current.output;
296 - }
297 -
298 - return null;
265 + return bailoutOnLowPriority(current, workInProgress);
266 }
267
268 // The current, flushed, state of this fiber is the alternate.
@@ -306,7 +273,7 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
273 return bailoutOnCurrent(current, workInProgress);
274 }
275
309 - if (!workInProgress.childInProgress &&
276 + if (workInProgress.memoizedProps &&
277 workInProgress.pendingProps === workInProgress.memoizedProps) {
278 return bailoutOnAlreadyFinishedWork(current, workInProgress);
279 }
@@ -322,10 +289,10 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
289 reconcileChildren(current, workInProgress, workInProgress.pendingProps);
290 // A yield component is just a placeholder, we can just run through the
291 // next one immediately.
325 - if (workInProgress.childInProgress) {
292 + if (workInProgress.child) {
293 return beginWork(
327 - workInProgress.childInProgress.alternate,
328 - workInProgress.childInProgress
294 + workInProgress.child.alternate,
295 + workInProgress.child
296 );
297 }
298 return null;
@@ -342,13 +309,13 @@ module.exports = function<T, P, I, C>(config : HostConfig<T, P, I, C>) {
309 updateCoroutineComponent(current, workInProgress);
310 // This doesn't take arbitrary time so we could synchronously just begin
311 // eagerly do the work of workInProgress.child as an optimization.
345 - if (workInProgress.childInProgress) {
312 + if (workInProgress.child) {
313 return beginWork(
347 - workInProgress.childInProgress.alternate,
348 - workInProgress.childInProgress
314 + workInProgress.child.alternate,
315 + workInProgress.child
316 );
317 }
351 - return workInProgress.childInProgress;
318 + return workInProgress.child;
319 case YieldComponent:
320 // A yield component is just a placeholder, we can just run through the
321 // next one immediately.