Fixed some missing operations that could happen after reload-and-profile
Brian Vaughn committed
Apr 1, 2019 at 14:29 UTC
f5f7cb5bdf7822a65b772ccdb901aa678f645c45
6 files changed
+65
-33
src/backend/index.js
+4
-1
@@ -23,7 +23,10 @@ export function initBackend(
23
rendererInterface: RendererInterface,
24
}) => {
25
agent.setRendererInterface(id, rendererInterface);
26
- rendererInterface.walkTree();
26
+
27
+ // Now that the Store and the renderer interface are connected,
28
+ // it's time to flush the pending operation codes to the frontend.
29
+ rendererInterface.flushInitialOperations();
30
}
31
),
32
src/backend/renderer.js
+50
-25
@@ -567,6 +567,7 @@ export function attach(
567
}
568
569
let pendingOperations: Uint32Array = new Uint32Array(0);
570
+ let pendingOperationsQueue: Array<Uint32Array> | null = [];
571
572
function addOperation(
573
newAction: Uint32Array,
@@ -604,7 +605,16 @@ export function attach(
605
// Let the frontend know about tree operations.
606
// The first value in this array will identify which root it corresponds to,
607
// so we do no longer need to dispatch a separate root-committed event.
607
- hook.emit('operations', pendingOperations);
608
+ if (pendingOperationsQueue !== null) {
609
+ // Until the frontend has been connected, store the tree operations.
610
+ // This will let us avoid walking the tree later when the frontend connects,
611
+ // and it enables the Profiler's reload-and-profile functionality to work as well.
612
+ pendingOperationsQueue.push(pendingOperations);
613
+ } else {
614
+ // If we've already connected to the frontend, just pass the operations through.
615
+ hook.emit('operations', pendingOperations);
616
+ }
617
+
618
pendingOperations = new Uint32Array(0);
619
}
620
@@ -914,31 +924,46 @@ export function attach(
924
// We don't patch any methods so there is no cleanup.
925
}
926
917
- function walkTree() {
918
- // Hydrate all the roots for the first time.
919
- hook.getFiberRoots(rendererID).forEach(root => {
920
- currentRootID = getFiberID(getPrimaryFiber(root.current));
927
+ function flushInitialOperations() {
928
+ const localPendingOperationsQueue = pendingOperationsQueue;
929
922
- if (isProfiling) {
923
- // If profiling is active, store commit time and duration, and the current interactions.
924
- // The frontend may request this information after profiling has stopped.
925
- currentCommitProfilingMetadata = {
926
- actualDurations: [],
927
- commitTime: performance.now() - profilingStartTime,
928
- interactions: Array.from(root.memoizedInteractions).map(
929
- (interaction: Interaction) => ({
930
- ...interaction,
931
- timestamp: interaction.timestamp - profilingStartTime,
932
- })
933
- ),
934
- maxActualDuration: 0,
935
- };
936
- }
930
+ pendingOperationsQueue = null;
931
938
- mountFiber(root.current, null);
939
- flushPendingEvents(root);
940
- currentRootID = -1;
941
- });
932
+ if (
933
+ localPendingOperationsQueue !== null &&
934
+ localPendingOperationsQueue.length > 0
935
+ ) {
936
+ // We may have already queued up some operations before the frontend connected
937
+ // If so, let the frontend know about them.
938
+ localPendingOperationsQueue.forEach(pendingOperations => {
939
+ hook.emit('operations', pendingOperations);
940
+ });
941
+ } else {
942
+ // If we have not been profiling, then we can just walk the tree and build up its current state as-is.
943
+ hook.getFiberRoots(rendererID).forEach(root => {
944
+ currentRootID = getFiberID(getPrimaryFiber(root.current));
945
+
946
+ if (isProfiling) {
947
+ // If profiling is active, store commit time and duration, and the current interactions.
948
+ // The frontend may request this information after profiling has stopped.
949
+ currentCommitProfilingMetadata = {
950
+ actualDurations: [],
951
+ commitTime: performance.now() - profilingStartTime,
952
+ interactions: Array.from(root.memoizedInteractions).map(
953
+ (interaction: Interaction) => ({
954
+ ...interaction,
955
+ timestamp: interaction.timestamp - profilingStartTime,
956
+ })
957
+ ),
958
+ maxActualDuration: 0,
959
+ };
960
+ }
961
+
962
+ mountFiber(root.current, null);
963
+ flushPendingEvents(root);
964
+ currentRootID = -1;
965
+ });
966
+ }
967
}
968
969
function handleCommitFiberUnmount(fiber) {
@@ -1623,6 +1648,7 @@ export function attach(
1648
1649
return {
1650
cleanup,
1651
+ flushInitialOperations,
1652
getCommitDetails,
1653
getFiberIDFromNative,
1654
getInteractions,
@@ -1641,6 +1667,5 @@ export function attach(
1667
setInState,
1668
startProfiling,
1669
stopProfiling,
1644
- walkTree,
1670
};
1671
}
src/backend/types.js
+1
-1
@@ -82,6 +82,7 @@ export type ProfilingSummary = {|
82
83
export type RendererInterface = {
84
cleanup: () => void,
85
+ flushInitialOperations: () => void,
86
getCommitDetails: (rootID: number, commitIndex: number) => CommitDetails,
87
getNativeFromReactElement?: ?(component: Fiber) => ?NativeType,
88
getFiberIDFromNative: (
@@ -108,7 +109,6 @@ export type RendererInterface = {
109
setInState: (id: number, path: Array<string | number>, value: any) => void,
110
startProfiling: () => void,
111
stopProfiling: () => void,
111
- walkTree: () => void,
112
};
113
114
export type Handler = (data: any) => void;
src/devtools/views/Profiler/CommitTreeBuilder.js
+1
-6
@@ -112,14 +112,9 @@ export function getCommitTree({
112
}
113
}
114
115
- console.error(
115
+ throw Error(
116
`getCommitTree(): Unable to reconstruct tree for root "${rootID}" and commit ${commitIndex}`
117
);
118
-
119
- return {
120
- nodes: new Map(),
121
- rootID,
122
- };
118
}
119
120
function recursivelyIniitliazeTree(
src/devtools/views/Profiler/FlamegraphChartBuilder.js
+5
@@ -56,6 +56,11 @@ export function getChartData({
56
idToDepthMap.set(id, currentDepth);
57
58
const node = ((nodes.get(id): any): Node);
59
+
60
+ if (node == null) {
61
+ throw Error(`Could not find node with id "${id}" in commit tree`);
62
+ }
63
+
64
const name = node.displayName || 'Unknown';
65
66
const selfDuration = calculateSelfDuration(id, commitTree, commitDetails);
src/devtools/views/Profiler/RankedChartBuilder.js
+4
@@ -41,6 +41,10 @@ export function getChartData({
41
actualDurations.forEach((actualDuration, id) => {
42
const node = ((nodes.get(id): any): Node);
43
44
+ if (node == null) {
45
+ throw Error(`Could not find node with id "${id}" in commit tree`);
46
+ }
47
+
48
// Don't show the root node in this chart.
49
if (node.parentID === 0) {
50
return;