Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 3 additions & 20 deletions docs/en/middleware/supplemental.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,38 +165,21 @@ r.mount();

Dojo provides a variety of optional middleware that widgets can include when needing to implement specific requirements.

## `cache`

Provides a simple widget-scoped cache that can persist small amounts of data between widget renders.

**API:**

```ts
import cache from '@dojo/framework/core/middleware/cache';
```

- `cache.get<T = any>(key: any): T | null`
- Retrieves the currently cached value for the specified `key`, or `null` on a cache miss.
- `cache.set<T = any>(key: any, value: T)`
- Stores the provided `value` in the cache against the specified `key`.
- `cache.clear()`
- Clears all values currently stored in the widget's local cache.

## `icache`

Composes [`cache`](/learn/middleware/available-middleware#cache) and [`invalidator`](/learn/middleware/core-render-middleware#invalidator) middleware functionality to provide a cache that supports lazy value resolution and automatic widget invalidation once a value becomes available.
A middleware that uses the [`invalidator`](/learn/middleware/core-render-middleware#invalidator) middleware functionality to provide a cache that supports lazy value resolution and automatic widget invalidation once a value becomes available. By default the cache will invalidate when a value is set in the cache, however there is an optional third argument on the set APIs that can be used to skip the invalidation when required.

**API:**

```ts
import icache from '@dojo/framework/core/middleware/icache';
```

- `icache.getOrSet<T = any>(key: any, value: any): T | undefined`
- `icache.getOrSet<T = any>(key: any, value: any, invalidate: boolean = true): T | undefined`
- Retrieves the cached value for the given `key`, if one exists, otherwise `value` is set. In both instances, `undefined` is returned if the cached value has not yet been resolved.
- `icache.get<T = any>(key: any): T | undefined`
- Retrieves the cached value for the given `key`, or `undefined` if either no value has been set, or if the value is still pending resolution.
- `icache.set(key: any, value: any)`
- `icache.set(key: any, value: any, invalidate: boolean = true)`
- Sets the provided `value` for the given `key`. If `value` is a function, it will be invoked in order to obtain the actual value to cache. If the function returns a promise, a 'pending' value will be cached until the final value is fully resolved. In all scenarios, once a value is available and has been stored in the cache, the widget will be marked as invalid so it can be re-rendered with the final value available.
- `icache.has(key: any): boolean`
- Returns `true` or `false` based in whether the key is set in the cache.
Expand Down
21 changes: 2 additions & 19 deletions docs/zh-CN/middleware/supplemental.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,23 +170,6 @@ r.mount();

Dojo 提供了多种可选的中间件,当部件需要实现特定需求时,可以包含这些中间件。

## `cache`

提供了一个简单的、部件内的缓存,可以在部件的多次渲染间保留少量数据。

**API:**

```ts
import cache from '@dojo/framework/core/middleware/cache';
```

- `cache.get<T = any>(key: any): T | null`
- 根据指定的 `key` 获取当前缓存值,如果缓存未命中则返回 `null`。
- `cache.set<T = any>(key: any, value: T)`
- 将提供的 `value` 存储在缓存中,并与指定的 `key` 关联。
- `cache.clear()`
- 清除当前在部件本地缓存中存储的所有值。

## `icache`

组合了 [`cache`](/learn/middleware/可用的中间件#cache) 和 [`invalidator`](/learn/middleware/核心渲染中间件#invalidator) 中间件功能,以提供一个缓存,支持延迟值的解析,并在值可用时自动让部件失效。
Expand All @@ -197,11 +180,11 @@ import cache from '@dojo/framework/core/middleware/cache';
import icache from '@dojo/framework/core/middleware/icache';
```

- `icache.getOrSet<T = any>(key: any, value: any): T | undefined`
- `icache.getOrSet<T = any>(key: any, value: any, invalidate: boolean = true): T | undefined`
- 如果存在的话,则返回根据 `key` 获取的值,否则就将 `key` 值设置为 `value`。在这两种情况下,如果缓存值尚未解析,则返回 `undefined`。
- `icache.get<T = any>(key: any): T | undefined`
- 根据 `key` 获取缓存值,如果未设置值或者该值处在挂起状态,则返回 `undefined`。
- `icache.set(key: any, value: any)`
- `icache.set(key: any, value: any, invalidate: boolean = true)`
- 将提供的 `value` 设置给指定的 `key`。如果 `value` 是一个函数,则将调用它以获取要缓存的实际值。如果函数返回的是 promise,则会先缓存一个“pending”值,直到解析出最终的值。在所有场景中,一旦一个值可用并存储到缓存中,该部件将被标记为无效,这样就可以使用最终的值重新渲染。
- `clear()`
- 清除当前在部件本地缓存中存储的所有值。
Expand Down
9 changes: 4 additions & 5 deletions src/core/middleware/block.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { create, defer, decrementBlockCount, incrementBlockCount } from '../vdom';
import cache from './cache';
import icache from './icache';

const blockFactory = create({ defer, cache, icache });
const blockFactory = create({ defer, icache });

export const block = blockFactory(({ middleware: { cache, icache, defer } }) => {
export const block = blockFactory(({ middleware: { icache, defer } }) => {
let id = 1;
return <T extends (...args: any[]) => any>(module: T) => {
return (...args: Parameters<T>): (ReturnType<T> extends Promise<infer U> ? U : ReturnType<T>) | null => {
const argsString = JSON.stringify(args);
const moduleId = cache.get(module) || id++;
cache.set(module, moduleId);
const moduleId = icache.get(module) || id++;
icache.set(module, moduleId, false);
const cachedValue = icache.getOrSet(`${moduleId}-${argsString}`, async () => {
incrementBlockCount();
const run = module(...args);
Expand Down
28 changes: 15 additions & 13 deletions src/core/middleware/cache.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { create, destroy } from '../vdom';
import Map from '../../shim/Map';
import has from './../has';
import { create } from '../vdom';
import icache from './icache';

const factory = create({ destroy });
const factory = create({ icache });

export const cache = factory(({ middleware: { destroy } }) => {
const cacheMap = new Map<string, any>();
destroy(() => {
cacheMap.clear();
});
export const cache = factory(({ middleware: { icache } }) => {
if (has('dojo-debug')) {
console.warn(
'The cache middleware has been deprecated. Please use the icache middleware instead, for details please see the documentation https://dojo.io/learn/middleware/available-middleware#icache'
);
}
return {
get<T = any>(key: any): T | undefined {
return cacheMap.get(key);
return icache.get(key);
},
set<T = any>(key: any, value: T): void {
cacheMap.set(key, value);
icache.set(key, value, false);
},
has(key: any): boolean {
return cacheMap.has(key);
return icache.has(key);
},
delete(key: any): void {
cacheMap.delete(key);
icache.delete(key);
},
clear(): void {
cacheMap.clear();
icache.clear();
}
};
});
Expand Down
60 changes: 35 additions & 25 deletions src/core/middleware/icache.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* tslint:disable:interface-name */
import { create, invalidator } from '../vdom';
import cache from './cache';
import Map from '../../shim/Map';
import { create, invalidator, destroy } from '../vdom';

const factory = create({ cache, invalidator });
const factory = create({ invalidator, destroy });

interface CacheWrapper {
status: 'pending' | 'resolved';
Expand All @@ -13,15 +13,18 @@ export interface ICacheResult<S = void> {
getOrSet: {
<T extends void extends S ? any : keyof S>(
key: void extends S ? any : T,
value: void extends S ? () => Promise<T> : () => Promise<S[T]>
value: void extends S ? () => Promise<T> : () => Promise<S[T]>,
invalidate?: boolean
): void extends S ? undefined | T : undefined | S[T];
<T extends void extends S ? any : keyof S>(
key: void extends S ? any : T,
value: void extends S ? () => T : () => S[T]
value: void extends S ? () => T : () => S[T],
invalidate?: boolean
): void extends S ? T : S[T];
<T extends void extends S ? any : keyof S>(
key: void extends S ? any : T,
value: void extends S ? T : S[T]
value: void extends S ? T : S[T],
invalidate?: boolean
): void extends S ? T : S[T];
};
get<T extends void extends S ? any : keyof S>(
Expand All @@ -30,15 +33,18 @@ export interface ICacheResult<S = void> {
set: {
<T extends void extends S ? any : keyof S>(
key: void extends S ? any : T,
value: void extends S ? () => Promise<T> : () => Promise<S[T]>
value: void extends S ? () => Promise<T> : () => Promise<S[T]>,
invalidate?: boolean
): void;
<T extends void extends S ? any : keyof S>(
key: void extends S ? any : T,
value: void extends S ? () => T : () => S[T]
value: void extends S ? () => T : () => S[T],
invalidate?: boolean
): void;
<T extends void extends S ? any : keyof S>(
key: void extends S ? any : T,
value: void extends S ? T : S[T]
value: void extends S ? T : S[T],
invalidate?: boolean
): void;
};
has<T extends void extends S ? any : keyof S>(key: void extends S ? any : T): boolean;
Expand All @@ -48,61 +54,65 @@ export interface ICacheResult<S = void> {

export function createICacheMiddleware<S = void>() {
const icache = factory(
({ middleware: { invalidator, cache } }): ICacheResult<S> => {
({ middleware: { invalidator, destroy } }): ICacheResult<S> => {
const cacheMap = new Map<string, CacheWrapper>();
destroy(() => {
cacheMap.clear();
});
return {
getOrSet(key: any, value: any): any | undefined {
let cachedValue = cache.get<CacheWrapper>(key);
getOrSet(key: any, value: any, invalidate = true): any | undefined {
let cachedValue = cacheMap.get(key);
if (!cachedValue) {
this.set(key, value);
this.set(key, value, invalidate);
}
cachedValue = cache.get<CacheWrapper>(key);
cachedValue = cacheMap.get(key);
if (!cachedValue || cachedValue.status === 'pending') {
return undefined;
}
return cachedValue.value;
},
get(key: any): any {
const cachedValue = cache.get<CacheWrapper>(key);
const cachedValue = cacheMap.get(key);
if (!cachedValue || cachedValue.status === 'pending') {
return undefined;
}
return cachedValue.value;
},
set(key: any, value: any): void {
set(key: any, value: any, invalidate = true): void {
if (typeof value === 'function') {
value = value();
if (value && typeof value.then === 'function') {
cache.set(key, {
cacheMap.set(key, {
status: 'pending',
value
});
value.then((result: any) => {
const cachedValue = cache.get<CacheWrapper>(key);
const cachedValue = cacheMap.get(key);
if (cachedValue && cachedValue.value === value) {
cache.set(key, {
cacheMap.set(key, {
status: 'resolved',
value: result
});
invalidator();
invalidate && invalidator();
}
});
return;
}
}
cache.set(key, {
cacheMap.set(key, {
status: 'resolved',
value
});
invalidator();
invalidate && invalidator();
},
has(key: any) {
return cache.has(key);
return cacheMap.has(key);
},
delete(key: any) {
cache.delete(key);
cacheMap.delete(key);
},
clear(): void {
cache.clear();
cacheMap.clear();
}
};
}
Expand Down
10 changes: 5 additions & 5 deletions src/core/middleware/intersection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import WeakMap from '../../shim/WeakMap';
import IntersectionObserver from '../../shim/IntersectionObserver';
import { create, node, invalidator, destroy } from '../vdom';
import cache from './cache';
import icache from './icache';
import {
IntersectionResult,
IntersectionGetOptions,
Expand All @@ -14,9 +14,9 @@ const defaultIntersection: IntersectionResult = Object.freeze({
isIntersecting: false
});

const factory = create({ cache, node, invalidator, destroy });
const factory = create({ icache, node, invalidator, destroy });

export const intersection = factory(({ middleware: { cache, node, invalidator, destroy } }) => {
export const intersection = factory(({ middleware: { icache, node, invalidator, destroy } }) => {
const handles: Function[] = [];
destroy(() => {
let handle: any;
Expand All @@ -32,13 +32,13 @@ export const intersection = factory(({ middleware: { cache, node, invalidator, d
root: rootNode
});
const details = { observer, entries, ...options };
cache.set(JSON.stringify(options), details);
icache.set(JSON.stringify(options), details, false);
handles.push(() => observer.disconnect());
return details;
}

function _getDetails(options: IntersectionGetOptions = {}): IntersectionDetail | undefined {
return cache.get(JSON.stringify(options));
return icache.get(JSON.stringify(options));
}

function _onIntersect(detailEntries: WeakMap<Element, IntersectionResult>) {
Expand Down
16 changes: 8 additions & 8 deletions src/core/middleware/theme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Theme, Classes, ClassNames } from './../interfaces';
import { create, invalidator, diffProperty, getRegistry } from '../vdom';
import cache from './cache';
import icache from './icache';
import injector from './injector';
import Injector from '../Injector';
import Set from '../../shim/Set';
Expand All @@ -27,14 +27,14 @@ function registerThemeInjector(theme: any, themeRegistry: Registry): Injector {
return themeInjector;
}

const factory = create({ invalidator, cache, diffProperty, injector, getRegistry }).properties<ThemeProperties>();
const factory = create({ invalidator, icache, diffProperty, injector, getRegistry }).properties<ThemeProperties>();

export const theme = factory(
({ middleware: { invalidator, cache, diffProperty, injector, getRegistry }, properties }) => {
({ middleware: { invalidator, icache, diffProperty, injector, getRegistry }, properties }) => {
let themeKeys = new Set();
diffProperty('theme', (current: ThemeProperties, next: ThemeProperties) => {
if (current.theme !== next.theme) {
cache.clear();
icache.clear();
invalidator();
}
});
Expand All @@ -53,7 +53,7 @@ export const theme = factory(
}
}
if (result) {
cache.clear();
icache.clear();
invalidator();
}
});
Expand All @@ -66,12 +66,12 @@ export const theme = factory(
}
}
injector.subscribe(INJECTED_THEME_KEY, () => {
cache.clear();
icache.clear();
invalidator();
});
return {
classes<T extends ClassNames>(css: T): T {
let theme = cache.get(css);
let theme = icache.get<T>(css);
if (theme) {
return theme;
}
Expand All @@ -95,7 +95,7 @@ export const theme = factory(
}
}
}
cache.set(css, theme);
icache.set(css, theme, false);
return theme;
},
set(css: Theme): void {
Expand Down
7 changes: 3 additions & 4 deletions src/testing/mocks/middleware/icache.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { create, invalidator } from '../../../core/vdom';
import { create, invalidator, destroy } from '../../../core/vdom';
import { DefaultMiddlewareResult } from '../../../core/interfaces';
import { cache } from '../../../core/middleware/cache';
import { icache } from '../../../core/middleware/icache';
import Map from '../../../shim/Map';

export function createICacheMock() {
const map = new Map<string, any>();
const factory = create({ cache, invalidator });
const factory = create({ destroy, invalidator });
const mockICacheFactory = factory(({ id, middleware, properties, children }) => {
const { callback } = icache();
const icacheMiddleware = callback({
id,
middleware: { invalidator: middleware.invalidator, cache: middleware.cache },
middleware: { invalidator: middleware.invalidator, destroy: middleware.destroy },
properties,
children
});
Expand Down
Loading