Reverted optimization to avoid re-sending inspected fiber unless it committed

This commit is contained in:
Brian Vaughn
2019-04-23 18:04:25 -07:00
parent 0aa7d2f800
commit 7262a30cf3
3 changed files with 50 additions and 34 deletions
+11 -11
View File
@@ -1,7 +1,6 @@
// @flow
import React, { createContext } from 'react';
import LRU from 'lru-cache';
// Cache implementation was forked from the React repo:
// https://github.com/facebook/react/blob/master/packages/react-cache/src/ReactCache.js
@@ -68,18 +67,23 @@ function readContext(Context, observedBits) {
const CacheContext = createContext(null);
type Config = {
useLRU?: boolean,
useWeakMap?: boolean,
};
const entries: Map<Resource<any, any, any>, Map<any, any> | LRU> = new Map();
const entries: Map<
Resource<any, any, any>,
Map<any, any> | WeakMap<any, any>
> = new Map();
const resourceConfigs: Map<Resource<any, any, any>, Config> = new Map();
function getEntriesForResource(resource: any): Map<any, any> | LRU {
function getEntriesForResource(
resource: any
): Map<any, any> | WeakMap<any, any> {
let entriesForResource = ((entries.get(resource): any): Map<any, any>);
if (entriesForResource === undefined) {
const config = resourceConfigs.get(resource);
entriesForResource =
config !== undefined && config.useLRU ? new LRU({ max: 10 }) : new Map();
config !== undefined && config.useWeakMap ? new WeakMap() : new Map();
entries.set(resource, entriesForResource);
}
return entriesForResource;
@@ -122,7 +126,7 @@ function accessResult<Input, Key, Value>(
}
}
export function createResource<Input, Key: string | number, Value>(
export function createResource<Input, Key, Value>(
fetch: Input => Thenable<Value>,
hashInput: Input => Key,
config?: Config = {}
@@ -134,11 +138,7 @@ export function createResource<Input, Key: string | number, Value>(
invalidate(key: Key): void {
const entriesForResource = getEntriesForResource(resource);
if (entriesForResource instanceof Map) {
entriesForResource.delete(key);
} else {
entriesForResource.set(key, undefined);
}
entriesForResource.delete(key);
},
read(input: Input): Value {
+3 -2
View File
@@ -68,8 +68,9 @@ export default class Store extends EventEmitter {
// At least one of the injected renderers contains (DEV only) owner metadata.
_hasOwnerMetadata: boolean = false;
// Map of ID to Element.
// Elements are mutable (for now) to avoid excessive cloning during tree updates.
// Map of ID to (mutable) Element.
// Elements are mutated to avoid excessive cloning during tree updates.
// The InspectedElementContext also relies on this mutability for its WeakMap usage.
_idToElement: Map<number, Element> = new Map();
// The user has imported a previously exported profiling session.
@@ -2,6 +2,7 @@
import React, {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
@@ -14,6 +15,7 @@ import { TreeStateContext } from './TreeContext';
import type {
DehydratedData,
Element,
InspectedElement,
} from 'src/devtools/views/Components/types';
import type { Resource, Thenable } from '../../cache';
@@ -31,10 +33,10 @@ type InProgressRequest = {|
resolveFn: ResolveFn,
|};
const inProgressRequests: Map<number, InProgressRequest> = new Map();
const resource: Resource<number, number, InspectedElement> = createResource(
(id: number) => {
let request = inProgressRequests.get(id);
const inProgressRequests: WeakMap<Element, InProgressRequest> = new WeakMap();
const resource: Resource<Element, Element, InspectedElement> = createResource(
(element: Element) => {
let request = inProgressRequests.get(element);
if (request != null) {
return request.promise;
}
@@ -44,12 +46,12 @@ const resource: Resource<number, number, InspectedElement> = createResource(
resolveFn = resolve;
});
inProgressRequests.set(id, { promise, resolveFn });
inProgressRequests.set(element, { promise, resolveFn });
return promise;
},
(id: number) => id,
{ useLRU: true }
(element: Element) => element,
{ useWeakMap: true }
);
type Props = {|
@@ -60,6 +62,18 @@ function InspectedElementContextController({ children }: Props) {
const bridge = useContext(BridgeContext);
const store = useContext(StoreContext);
const read = useCallback(
(id: number) => {
const element = store.getElementByID(id);
if (element !== null) {
return resource.read(element);
} else {
return null;
}
},
[store]
);
// It's very important that this context consumes selectedElementID and not inspectedElementID.
// Otherwise the effect that sends the "inspect" message across the bridge-
// would itself be blocked by the same render that suspends (waiting for the data).
@@ -81,16 +95,19 @@ function InspectedElementContextController({ children }: Props) {
state: hydrateHelper(inspectedElement.state),
}: any): InspectedElement);
const request = inProgressRequests.get(id);
if (request != null) {
inProgressRequests.delete(id);
request.resolveFn(inspectedElement);
} else {
resource.write(id, inspectedElement);
const element = store.getElementByID(id);
if (element !== null) {
const request = inProgressRequests.get(element);
if (request != null) {
inProgressRequests.delete(element);
request.resolveFn(inspectedElement);
} else {
resource.write(element, inspectedElement);
// Schedule update with React if the curently-selected element has been invalidated.
if (id === selectedElementID) {
setCount(count => count + 1);
// Schedule update with React if the curently-selected element has been invalidated.
if (id === selectedElementID) {
setCount(count => count + 1);
}
}
}
}
@@ -98,7 +115,7 @@ function InspectedElementContextController({ children }: Props) {
bridge.addListener('inspectedElement', onInspectedElement);
return () => bridge.removeListener('inspectedElement', onInspectedElement);
}, [bridge, selectedElementID]);
}, [bridge, selectedElementID, store]);
// This effect handler polls for updates on the currently selected element.
useEffect(() => {
@@ -145,12 +162,10 @@ function InspectedElementContextController({ children }: Props) {
}, [bridge, selectedElementID, store]);
const value = useMemo(
() => ({
read: resource.read,
}),
() => ({ read }),
// Count is used to invalidate the cache and schedule an update with React.
// eslint-disable-next-line react-hooks/exhaustive-deps
[count]
[count, read]
);
return (