Fixed bug with cache invalidation

This commit is contained in:
Brian Vaughn
2019-04-22 15:18:32 -07:00
parent 64bc49d523
commit 64bb2d31f9
3 changed files with 54 additions and 37 deletions
+6 -3
View File
@@ -1,6 +1,6 @@
// @flow
import { createResource, invalidateResources } from './cache';
import { createResource } from './cache';
import Store from './store';
import {
getCommitTree,
@@ -297,8 +297,11 @@ export default class ProfilingCache {
});
invalidate() {
// Invalidate Susepnse caches.
invalidateResources();
// Invalidate Suspense caches.
this.CommitDetails.clear();
this.FiberCommits.clear();
this.Interactions.clear();
this.ProfilingSummary.clear();
// Invalidate non-Suspense caches too.
invalidateCommitTrees();
+26 -5
View File
@@ -39,6 +39,7 @@ type RejectedResult = {|
type Result<Value> = PendingResult | ResolvedResult<Value> | RejectedResult;
export type Resource<Input, Key, Value> = {
clear(): void,
invalidate(Key): void,
read(Input): Value,
preload(Input): void,
@@ -66,7 +67,23 @@ function readContext(Context, observedBits) {
const CacheContext = createContext(null);
type Config = {
useLRU?: boolean,
};
const entries: Map<Resource<any, any, any>, Map<any, any>> = new Map();
const resourceConfigs: Map<Resource<any, any, any>, Config> = new Map();
function getEntriesForResource(resource: any): Map<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();
entries.set(resource, entriesForResource);
}
return entriesForResource;
}
function accessResult<Input, Key, Value>(
resource: any,
@@ -74,7 +91,7 @@ function accessResult<Input, Key, Value>(
input: Input,
key: Key
): Result<Value> {
const entriesForResource = ((entries.get(resource): any): Map<any, any>);
const entriesForResource = getEntriesForResource(resource);
const entry = entriesForResource.get(key);
if (entry === undefined) {
const thenable = fetch(input);
@@ -108,11 +125,15 @@ function accessResult<Input, Key, Value>(
export function createResource<Input, Key: string | number, Value>(
fetch: Input => Thenable<Value>,
hashInput: Input => Key,
useLRU?: boolean = false
config?: Config = {}
): Resource<Input, Key, Value> {
const resource = {
clear(): void {
entries.delete(resource);
},
invalidate(key: Key): void {
const entriesForResource = ((entries.get(resource): any): Map<any, any>);
const entriesForResource = getEntriesForResource(resource);
if (entriesForResource instanceof Map) {
entriesForResource.delete(key);
} else {
@@ -156,7 +177,7 @@ export function createResource<Input, Key: string | number, Value>(
},
write(key: Key, value: Value): void {
const entriesForResource = ((entries.get(resource): any): Map<any, any>);
const entriesForResource = getEntriesForResource(resource);
const resolvedResult: ResolvedResult<Value> = {
status: Resolved,
@@ -167,7 +188,7 @@ export function createResource<Input, Key: string | number, Value>(
},
};
entries.set(resource, useLRU ? new LRU({ max: 10 }) : new Map());
resourceConfigs.set(resource, config);
return resource;
}
@@ -31,6 +31,27 @@ 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);
if (request != null) {
return request.promise;
}
let resolveFn = ((null: any): ResolveFn);
const promise = new Promise(resolve => {
resolveFn = resolve;
});
inProgressRequests.set(id, { promise, resolveFn });
return promise;
},
(id: number) => id,
{ useLRU: true }
);
type Props = {|
children: React$Node,
|};
@@ -42,34 +63,6 @@ function InspectedElementContextController({ children }: Props) {
const [count, setCount] = useState<number>(0);
const inProgressRequests = useMemo<Map<number, InProgressRequest>>(
() => new Map(),
[]
);
const resource = useMemo<Resource<number, number, InspectedElement>>(
() =>
createResource(
(id: number) => {
let request = inProgressRequests.get(id);
if (request != null) {
return request.promise;
}
let resolveFn = ((null: any): ResolveFn);
const promise = new Promise(resolve => {
resolveFn = resolve;
});
inProgressRequests.set(id, { promise, resolveFn });
return promise;
},
(id: number) => id
),
[inProgressRequests]
);
// This effect handler invalidates the suspense cache and schedules rendering updates with React.
useEffect(() => {
const onInspectedElement = (
@@ -103,7 +96,7 @@ function InspectedElementContextController({ children }: Props) {
bridge.addListener('inspectedElement', onInspectedElement);
return () => bridge.removeListener('inspectedElement', onInspectedElement);
}, [bridge, inProgressRequests, inspectedElementID, resource]);
}, [bridge, inspectedElementID]);
// This effect handler polls for updates on the currently selected element.
useEffect(() => {