@samitouri / QOS-React / commits / 811084d74e

Use the tag instead of stage field for coroutine stages

This gets rid of a field that we only need for coroutines. We might need this if we have multi phase handlers in the future but then maybe we can just use multiple tags.

Sebastian Markbage committed May 31, 2016 at 13:33 UTC 811084d74e7fefe09383e4ff39ed721b16d6a26f
4 files changed +38 -39
src/renderers/shared/fiber/ReactFiber.js
-5
@@ -51,9 +51,6 @@ export type Fiber = {
51 // if this returns multiple values. Such as a fragment.
52 output: any, // This type will be more specific once we overload the tag.
53
54 - // Used by multi-stage coroutines.
55 - stage: number, // Consider reusing the tag field instead.
56 -
54 // This will be used to quickly determine if a subtree has no pending changes.
55 hasPendingChanges: bool,
56
@@ -78,8 +75,6 @@ var createFiber = function(tag : number, key : null | string) : Fiber {
75 input: null,
76 output: null,
77
81 - stage: 0,
82 -
78 hasPendingChanges: true,
79
80 stateNode: null,
src/renderers/shared/fiber/ReactFiberBeginWork.js
+5 -2
@@ -23,6 +23,7 @@ var {
23 ClassComponent,
24 HostComponent,
25 CoroutineComponent,
26 + CoroutineHandlerPhase,
27 YieldComponent,
28 } = ReactTypesOfWork;
29
@@ -97,9 +98,11 @@ function beginWork(unitOfWork : Fiber) : ?Fiber {
98 case HostComponent:
99 updateHostComponent(unitOfWork);
100 break;
101 + case CoroutineHandlerPhase:
102 + // This is a restart. Reset the tag to the initial phase.
103 + unitOfWork.tag = CoroutineComponent;
104 + // Intentionally fall through since this is now the same.
105 case CoroutineComponent:
101 - // Reset the stage to zero.
102 - unitOfWork.stage = 0;
106 updateCoroutineComponent(unitOfWork);
107 // This doesn't take arbitrary time so we could synchronously just begin
108 // eagerly do the work of unitOfWork.child as an optimization.
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+31 -31
@@ -25,6 +25,7 @@ var {
25 ClassComponent,
26 HostComponent,
27 CoroutineComponent,
28 + CoroutineHandlerPhase,
29 YieldComponent,
30 } = ReactTypesOfWork;
31
@@ -52,43 +53,37 @@ function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
53 }
54 }
55
55 -function handleCoroutine(unitOfWork : Fiber) {
56 +function moveCoroutineToHandlerPhase(unitOfWork : Fiber) {
57 var coroutine = (unitOfWork.input : ?ReactCoroutine);
58 if (!coroutine) {
59 throw new Error('Should be resolved by now');
60 }
61
61 - if (unitOfWork.stage === 0) {
62 - // First step of the coroutine has completed. Now we need to do the second.
63 - // TODO: It would be nice to have a multi stage coroutine represented by a
64 - // single component, or at least tail call optimize nested ones.
65 - // TODO: If we end up not using multi stage coroutines, we could also reuse
66 - // the tag field to switch between the two stages.
67 - unitOfWork.stage = 1;
62 + // First step of the coroutine has completed. Now we need to do the second.
63 + // TODO: It would be nice to have a multi stage coroutine represented by a
64 + // single component, or at least tail call optimize nested ones. Currently
65 + // that requires additional fields that we don't want to add to the fiber.
66 + // So this requires nested handlers.
67 + unitOfWork.tag = CoroutineHandlerPhase;
68
69 - // Build up the yields.
70 - // TODO: Compare this to a generator or opaque helpers like Children.
71 - var yields : Array<ReifiedYield> = [];
72 - var child = unitOfWork.child;
73 - while (child) {
74 - recursivelyFillYields(yields, child.output);
75 - child = child.sibling;
76 - }
77 - var fn = coroutine.handler;
78 - var props = coroutine.props;
79 - var nextChildren = fn(props, yields);
80 -
81 - unitOfWork.stateNode = ReactChildFiber.reconcileChildFibers(
82 - unitOfWork,
83 - unitOfWork.stateNode,
84 - nextChildren
85 - );
86 - return unitOfWork.stateNode;
87 - } else {
88 - // The coroutine is now complete.
89 - transferOutput(unitOfWork.stateNode, unitOfWork);
90 - return null;
69 + // Build up the yields.
70 + // TODO: Compare this to a generator or opaque helpers like Children.
71 + var yields : Array<ReifiedYield> = [];
72 + var child = unitOfWork.child;
73 + while (child) {
74 + recursivelyFillYields(yields, child.output);
75 + child = child.sibling;
76 }
77 + var fn = coroutine.handler;
78 + var props = coroutine.props;
79 + var nextChildren = fn(props, yields);
80 +
81 + unitOfWork.stateNode = ReactChildFiber.reconcileChildFibers(
82 + unitOfWork,
83 + unitOfWork.stateNode,
84 + nextChildren
85 + );
86 + return unitOfWork.stateNode;
87 }
88
89 exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
@@ -106,7 +101,12 @@ exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
101 break;
102 case CoroutineComponent:
103 console.log('/coroutine component', unitOfWork.input.handler.name);
109 - return handleCoroutine(unitOfWork);
104 + return moveCoroutineToHandlerPhase(unitOfWork);
105 + case CoroutineHandlerPhase:
106 + transferOutput(unitOfWork.stateNode, unitOfWork);
107 + // Reset the tag to now be a first phase coroutine.
108 + unitOfWork.tag = CoroutineComponent;
109 + break;
110 case YieldComponent:
111 // Does nothing.
112 break;
src/renderers/shared/fiber/ReactTypesOfWork.js
+2 -1
@@ -18,7 +18,8 @@ var TypesOfWork = {
18 ClassComponent: 2,
19 HostComponent: 3,
20 CoroutineComponent: 4,
21 - YieldComponent: 5,
21 + CoroutineHandlerPhase: 5,
22 + YieldComponent: 6,
23 };
24
25 module.exports = TypesOfWork;