@samitouri / QOS-React-2 / commits / 5afd8cd704

Improve Fiber debugger (#8767)

* Simplify the hooks * Capture completion at the right moment * Animate the scroll with the fiber on the stack * Better display priorities

Dan Abramov committed Jan 13, 2017 at 04:41 UTC 5afd8cd704356cf7928ed6a1763e8fab6e496032
3 files changed +96 -70
examples/fiber/debugger/src/App.js
+13 -36
@@ -61,52 +61,39 @@ class App extends Component {
61 onUpdateContainer: (root) => {
62 currentRoot = root;
63 },
64 - onWillBeginWork: (fiber) => {
64 + onBeginWork: (fiber) => {
65 const fibers = getFiberState(currentRoot, fiber);
66 const stage = currentStage;
67 this.setState(({ history }) => ({
68 history: [
69 ...history, {
70 - action: 'willBeginWork',
70 + action: 'BEGIN',
71 fibers,
72 stage
73 }
74 ]
75 }));
76 },
77 - onDidBeginWork: (fiber) => {
77 + onCompleteWork: (fiber) => {
78 const fibers = getFiberState(currentRoot, fiber);
79 const stage = currentStage;
80 this.setState(({ history }) => ({
81 history: [
82 ...history, {
83 - action: 'didBeginWork',
83 + action: 'COMPLETE',
84 fibers,
85 stage
86 }
87 ]
88 }));
89 },
90 - onWillCompleteWork: (fiber) => {
90 + onCommitWork: (fiber) => {
91 const fibers = getFiberState(currentRoot, fiber);
92 const stage = currentStage;
93 this.setState(({ history }) => ({
94 history: [
95 ...history, {
96 - action: 'willCompleteWork',
97 - fibers,
98 - stage
99 - }
100 - ]
101 - }));
102 - },
103 - onDidCompleteWork: (fiber) => {
104 - const fibers = getFiberState(currentRoot, fiber);
105 - const stage = currentStage;
106 - this.setState(({ history }) => ({
107 - history: [
108 - ...history, {
109 - action: 'didCompleteWork',
96 + action: 'COMMIT',
97 fibers,
98 stage
99 }
@@ -116,6 +103,11 @@ class App extends Component {
103 };
104 window.React = React;
105 window.ReactNoop = ReactNoop;
106 + window.expect = () => ({
107 + toBe() {},
108 + toContain() {},
109 + toEqual() {},
110 + });
111 window.log = s => currentStage = s;
112 // eslint-disable-next-line
113 eval(window.Babel.transform(code, {
@@ -149,26 +141,10 @@ class App extends Component {
141
142 const { fibers, action, stage } = history[currentStep] || {};
143 let friendlyAction;
152 -
144 if (fibers) {
145 let wipFiber = fibers.descriptions[fibers.workInProgressID];
146 let friendlyFiber = wipFiber.type || wipFiber.tag + ' #' + wipFiber.id;
156 - switch (action) {
157 - case 'willBeginWork':
158 - friendlyAction = 'Before BEGIN phase on ' + friendlyFiber;
159 - break;
160 - case 'didBeginWork':
161 - friendlyAction = 'After BEGIN phase on ' + friendlyFiber;
162 - break;
163 - case 'willCompleteWork':
164 - friendlyAction = 'Before COMPLETE phase on ' + friendlyFiber;
165 - break;
166 - case 'didCompleteWork':
167 - friendlyAction = 'After COMPLETE phase on ' + friendlyFiber;
168 - break;
169 - default:
170 - throw new Error('Unknown action');
171 - }
147 + friendlyAction = `After ${action} on ${friendlyFiber}`;
148 }
149
150 return (
@@ -190,6 +166,7 @@ class App extends Component {
166 }}>
167 <input
168 type="range"
169 + style={{ width: '25%' }}
170 min={0}
171 max={history.length - 1}
172 value={currentStep}
examples/fiber/debugger/src/Fibers.js
+71 -9
@@ -58,17 +58,26 @@ function Graph(props) {
58
59 dagre.layout(g);
60
61 + var activeNode = g.nodes().map(v => g.node(v)).find(node =>
62 + node.label.props.isActive
63 + );
64 + const [winX, winY] = [window.innerWidth / 2, window.innerHeight / 2]
65 + var focusDx = activeNode ? (winX - activeNode.x) : 0;
66 + var focusDy = activeNode ? (winY - activeNode.y) : 0;
67 +
68 var nodes = g.nodes().map(v => {
69 var node = g.node(v);
70 return (
71 <Motion style={{
65 - x: props.isDragging ? node.x : spring(node.x),
66 - y: props.isDragging ? node.y : spring(node.y)
72 + x: props.isDragging ? node.x + focusDx : spring(node.x + focusDx),
73 + y: props.isDragging ? node.y + focusDy : spring(node.y + focusDy)
74 }} key={node.label.key}>
75 {interpolatingStyle =>
76 React.cloneElement(node.label, {
77 x: interpolatingStyle.x + props.dx,
71 - y: interpolatingStyle.y + props.dy
78 + y: interpolatingStyle.y + props.dy,
79 + vanillaX: node.x,
80 + vanillaY: node.y,
81 })
82 }
83 </Motion>
@@ -80,8 +89,8 @@ function Graph(props) {
89 let idx = 0;
90 return (
91 <Motion style={edge.points.reduce((bag, point) => {
83 - bag[idx + ':x'] = props.isDragging ? point.x : spring(point.x);
84 - bag[idx + ':y'] = props.isDragging ? point.y : spring(point.y);
92 + bag[idx + ':x'] = props.isDragging ? point.x + focusDx : spring(point.x + focusDx);
93 + bag[idx + ':y'] = props.isDragging ? point.y + focusDy : spring(point.y + focusDy);
94 idx++;
95 return bag;
96 }, {})} key={edge.label.key}>
@@ -131,7 +140,9 @@ function Vertex(props) {
140 overflow: 'hidden',
141 padding: '4px',
142 wordWrap: 'break-word'
134 - }} {...props} />
143 + }}>
144 + {props.children}
145 + </div>
146 );
147 }
148 Vertex.isVertex = true;
@@ -196,6 +207,25 @@ function Edge(props) {
207 }
208 Edge.isEdge = true;
209
210 +function formatPriority(priority) {
211 + switch (priority) {
212 + case 1:
213 + return 'synchronous';
214 + case 2:
215 + return 'task';
216 + case 3:
217 + return 'animation';
218 + case 4:
219 + return 'hi-pri work';
220 + case 5:
221 + return 'lo-pri work';
222 + case 6:
223 + return 'offscreen work';
224 + default:
225 + throw new Error('Unknown priority.');
226 + }
227 +}
228 +
229 export default function Fibers({ fibers, show, ...rest }) {
230 const items = Object.keys(fibers.descriptions).map(id =>
231 fibers.descriptions[id]
@@ -216,12 +246,18 @@ export default function Fibers({ fibers, show, ...rest }) {
246 ...rest.style,
247 transform: null
248 }}>
219 - <Graph className="graph" dx={dx} dy={dy} isDragging={isDragging}>
249 + <Graph
250 + className="graph"
251 + dx={dx}
252 + dy={dy}
253 + isDragging={isDragging}
254 + >
255 {items.map(fiber => [
256 <Vertex
257 key={fiber.id}
258 width={200}
224 - height={100}>
259 + height={100}
260 + isActive={fiber.id === fibers.workInProgressID}>
261 <div
262 style={{
263 width: '100%',
@@ -233,7 +269,33 @@ export default function Fibers({ fibers, show, ...rest }) {
269 <br />
270 {fiber.type}
271 <br />
236 - <small>Priority: {fiber.pendingWorkPriority} pend, {fiber.progressedPriority} prog</small>
272 + {fibers.currentIDs.indexOf(fiber.id) === -1 ?
273 + <small>
274 + {fiber.pendingWorkPriority !== 0 && [
275 + <span style={{
276 + fontWeight: fiber.pendingWorkPriority <= fiber.progressedPriority ?
277 + 'bold' :
278 + 'normal'
279 + }}>
280 + Needs: {formatPriority(fiber.pendingWorkPriority)}
281 + </span>,
282 + <br />
283 + ]}
284 + {fiber.progressedPriority !== 0 && [
285 + `Finished: ${formatPriority(fiber.progressedPriority)}`,
286 + <br />
287 + ]}
288 + {fiber.memoizedProps !== null && fiber.pendingProps !== null && [
289 + fiber.memoizedProps === fiber.pendingProps ?
290 + 'Can reuse memoized.' :
291 + 'Cannot reuse memoized.',
292 + <br />
293 + ]}
294 + </small> :
295 + <small>
296 + Committed
297 + </small>
298 + }
299 </div>
300 </Vertex>,
301 fiber.child && show.child &&
src/renderers/shared/fiber/ReactFiberScheduler.js
+12 -25
@@ -396,6 +396,9 @@ module.exports = function<T, P, I, TI, PI, C, CX>(config : HostConfig<T, P, I, T
396 }
397
398 isCommitting = false;
399 + if (__DEV__ && ReactFiberInstrumentation.debugTool) {
400 + ReactFiberInstrumentation.debugTool.onCommitWork(finishedWork);
401 + }
402
403 // If we caught any errors during this commit, schedule their boundaries
404 // to update.
@@ -448,6 +451,9 @@ module.exports = function<T, P, I, TI, PI, C, CX>(config : HostConfig<T, P, I, T
451 resetWorkPriority(workInProgress);
452
453 if (next) {
454 + if (__DEV__ && ReactFiberInstrumentation.debugTool) {
455 + ReactFiberInstrumentation.debugTool.onCompleteWork(workInProgress);
456 + }
457 // If completing this work spawned new work, do that next. We'll come
458 // back here again.
459 return next;
@@ -483,6 +489,10 @@ module.exports = function<T, P, I, TI, PI, C, CX>(config : HostConfig<T, P, I, T
489 }
490 }
491
492 + if (__DEV__ && ReactFiberInstrumentation.debugTool) {
493 + ReactFiberInstrumentation.debugTool.onCompleteWork(workInProgress);
494 + }
495 +
496 if (siblingFiber) {
497 // If there is more work to do in this returnFiber, do that next.
498 return siblingFiber;
@@ -507,32 +517,21 @@ module.exports = function<T, P, I, TI, PI, C, CX>(config : HostConfig<T, P, I, T
517 }
518
519 function performUnitOfWork(workInProgress : Fiber) : ?Fiber {
510 -
520 // The current, flushed, state of this fiber is the alternate.
521 // Ideally nothing should rely on this, but relying on it here
522 // means that we don't need an additional field on the work in
523 // progress.
524 const current = workInProgress.alternate;
525
517 - if (__DEV__ && ReactFiberInstrumentation.debugTool) {
518 - ReactFiberInstrumentation.debugTool.onWillBeginWork(workInProgress);
519 - }
526 // See if beginning this work spawns more work.
527 let next = beginWork(current, workInProgress, nextPriorityLevel);
522 -
528 if (__DEV__ && ReactFiberInstrumentation.debugTool) {
524 - ReactFiberInstrumentation.debugTool.onDidBeginWork(workInProgress);
529 + ReactFiberInstrumentation.debugTool.onBeginWork(workInProgress);
530 }
531
532 if (!next) {
528 - if (__DEV__ && ReactFiberInstrumentation.debugTool) {
529 - ReactFiberInstrumentation.debugTool.onWillCompleteWork(workInProgress);
530 - }
533 // If this doesn't spawn new work, complete the current work.
534 next = completeUnitOfWork(workInProgress);
533 - if (__DEV__ && ReactFiberInstrumentation.debugTool) {
534 - ReactFiberInstrumentation.debugTool.onDidCompleteWork(workInProgress);
535 - }
535 }
536
537 ReactCurrentOwner.current = null;
@@ -540,8 +539,6 @@ module.exports = function<T, P, I, TI, PI, C, CX>(config : HostConfig<T, P, I, T
539 ReactDebugCurrentFiber.current = null;
540 }
541
543 -
544 -
542 return next;
543 }
544
@@ -553,25 +550,15 @@ module.exports = function<T, P, I, TI, PI, C, CX>(config : HostConfig<T, P, I, T
550 // progress.
551 const current = workInProgress.alternate;
552
556 - if (__DEV__ && ReactFiberInstrumentation.debugTool) {
557 - ReactFiberInstrumentation.debugTool.onWillBeginWork(workInProgress);
558 - }
553 // See if beginning this work spawns more work.
554 let next = beginFailedWork(current, workInProgress, nextPriorityLevel);
561 -
555 if (__DEV__ && ReactFiberInstrumentation.debugTool) {
563 - ReactFiberInstrumentation.debugTool.onDidBeginWork(workInProgress);
556 + ReactFiberInstrumentation.debugTool.onBeginWork(workInProgress);
557 }
558
559 if (!next) {
567 - if (__DEV__ && ReactFiberInstrumentation.debugTool) {
568 - ReactFiberInstrumentation.debugTool.onWillCompleteWork(workInProgress);
569 - }
560 // If this doesn't spawn new work, complete the current work.
561 next = completeUnitOfWork(workInProgress);
572 - if (__DEV__ && ReactFiberInstrumentation.debugTool) {
573 - ReactFiberInstrumentation.debugTool.onDidCompleteWork(workInProgress);
574 - }
562 }
563
564 ReactCurrentOwner.current = null;