Skip to content

Commit e4ac35c

Browse files
committed
support for low priority
1 parent 582f452 commit e4ac35c

File tree

4 files changed

+53
-12
lines changed

4 files changed

+53
-12
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ import { IDBCache } from '@instructure/idb-cache';
2929
// Initialize the cache
3030
const cache = new IDBCache({
3131
cacheKey: 'your-secure-key',
32-
cacheBuster: 'unique-cache-buster', // Doubles as salt
33-
// dbName?: string;
32+
cacheBuster: 'unique-cache-buster',
3433
// chunkSize?: number;
35-
// maxTotalChunks?: number
3634
// cleanupInterval?: number;
37-
// pbkdf2Iterations?: number;
38-
// gcTime?: number;
35+
// dbName?: string;
3936
// debug?: boolean,
37+
// gcTime?: number;
38+
// maxTotalChunks?: number
39+
// pbkdf2Iterations?: number;
40+
// priority?: "normal" | "low"
4041
});
4142

4243
// Store an item

packages/idb-cache-app/src/App.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ const App = () => {
7272
return stored ? Number.parseInt(stored, 10) : DEFAULT_MAX_CHUNKS_STORED;
7373
},
7474
);
75+
const [priority, setPriority] = useState<"normal" | "low">(() => {
76+
const stored = localStorage.priority;
77+
return ["normal", "low"].includes(stored) ? stored : "normal";
78+
});
7579

7680
const [cacheReady, setCacheReady] = useState<boolean>(false);
7781

@@ -110,6 +114,7 @@ const App = () => {
110114
debug: true,
111115
chunkSize: chunkSize,
112116
maxTotalChunks: maxTotalChunksStored,
117+
priority,
113118
});
114119

115120
if (!isCancelled) {
@@ -138,12 +143,16 @@ const App = () => {
138143
setCacheReady(false);
139144
}
140145
};
141-
}, [chunkSize, maxTotalChunksStored]);
146+
}, [chunkSize, maxTotalChunksStored, priority]);
142147

143148
useEffect(() => {
144149
localStorage.setItem("maxTotalChunksStored", String(maxTotalChunksStored));
145150
}, [maxTotalChunksStored]);
146151

152+
useEffect(() => {
153+
localStorage.setItem("priority", String(priority));
154+
}, [priority]);
155+
147156
const encryptAndStore = useCallback(async () => {
148157
const cache = cacheRef.current;
149158
if (!cache) {
@@ -401,7 +410,7 @@ const App = () => {
401410
<WrappedFlexItem>
402411
<RadioInputGroup
403412
name="priority"
404-
defaultValue="normal"
413+
value={priority}
405414
description={
406415
<Flex alignItems="end">
407416
<Flex.Item as="div">
@@ -419,6 +428,9 @@ const App = () => {
419428
</Flex>
420429
}
421430
variant="toggle"
431+
onChange={(e) => {
432+
setPriority(e.target.value === "low" ? "low" : "normal");
433+
}}
422434
>
423435
<RadioInput label="Normal" value="normal" />
424436
<RadioInput label="Low" value="low" />

packages/idb-cache/src/index.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export class IDBCache implements AsyncStorage {
115115
private cacheBuster: string;
116116
private debug: boolean;
117117
private maxTotalChunks?: number;
118+
private priority: "normal" | "low" = "normal";
118119

119120
constructor(config: IDBCacheConfig) {
120121
const {
@@ -127,6 +128,7 @@ export class IDBCache implements AsyncStorage {
127128
cleanupInterval = CLEANUP_INTERVAL,
128129
pbkdf2Iterations = DEFAULT_PBKDF2_ITERATIONS,
129130
maxTotalChunks,
131+
priority = "normal",
130132
} = config;
131133

132134
this.storeName = "cache";
@@ -139,6 +141,7 @@ export class IDBCache implements AsyncStorage {
139141
this.pbkdf2Iterations = pbkdf2Iterations;
140142
this.maxTotalChunks = maxTotalChunks;
141143
this.pendingRequests = new Map();
144+
this.priority = priority;
142145

143146
if (!window.indexedDB)
144147
throw new DatabaseError("IndexedDB is not supported.");
@@ -230,6 +233,9 @@ export class IDBCache implements AsyncStorage {
230233
public async cleanup(): Promise<void> {
231234
try {
232235
const db = await this.dbReadyPromise;
236+
if (this.priority === "low") {
237+
await waitForAnimationFrame();
238+
}
233239
const transaction = db.transaction(this.storeName, "readwrite");
234240
const store = transaction.store;
235241
const timestampIndex = store.index("byTimestamp");
@@ -407,7 +413,9 @@ export class IDBCache implements AsyncStorage {
407413
if (!this.dbReadyPromise) return null;
408414
await this.ensureWorkerInitialized();
409415

410-
await waitForAnimationFrame();
416+
if (this.priority === "low") {
417+
await waitForAnimationFrame();
418+
}
411419
const db = await this.dbReadyPromise;
412420
const baseKey = await deterministicUUID(`${this.cacheKey}:${itemKey}`);
413421
const now = Date.now();
@@ -544,11 +552,16 @@ export class IDBCache implements AsyncStorage {
544552
if (!this.dbReadyPromise) return;
545553
await this.ensureWorkerInitialized();
546554

547-
await waitForAnimationFrame();
555+
if (this.priority === "low") {
556+
await waitForAnimationFrame();
557+
}
548558
const db = await this.dbReadyPromise;
549559
const baseKey = await deterministicUUID(`${this.cacheKey}:${itemKey}`);
550560
const expirationTimestamp = Date.now() + this.gcTime;
551561

562+
if (this.priority === "low") {
563+
await waitForAnimationFrame();
564+
}
552565
const existingChunkKeys = await getAllChunkKeysForBaseKey(
553566
db,
554567
this.storeName,
@@ -570,15 +583,22 @@ export class IDBCache implements AsyncStorage {
570583
const chunk = value.slice(i, i + this.chunkSize);
571584
const chunkIndex = Math.floor(i / this.chunkSize);
572585

586+
if (this.priority === "low") {
587+
await waitForAnimationFrame();
588+
}
573589
const chunkHash = await deterministicUUID(
574-
`${this.cacheKey}:${this.cacheBuster}:${chunk}`
590+
`${this.cacheKey}:${this.cacheBuster}:${chunk}`,
591+
this.priority
575592
);
576593
const chunkKey = generateChunkKey(baseKey, chunkIndex, chunkHash);
577594
newChunkKeys.add(chunkKey);
578595

579596
const isLastChunk = chunkIndex === totalChunks - 1;
580597

581598
if (existingChunkKeysSet.has(chunkKey)) {
599+
if (this.priority === "low") {
600+
await waitForAnimationFrame();
601+
}
582602
const existingChunk = await db.get(this.storeName, chunkKey);
583603
if (
584604
existingChunk &&
@@ -636,7 +656,9 @@ export class IDBCache implements AsyncStorage {
636656
}
637657

638658
await Promise.all(operationPromises);
639-
659+
if (this.priority === "low") {
660+
await waitForAnimationFrame();
661+
}
640662
await tx.done;
641663

642664
const duration = Date.now() - startTime;

packages/idb-cache/src/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ export function generateUUIDFromHash(hashHex: string): string {
5151
* @param itemKey - The item key.
5252
* @returns A deterministic UUID string.
5353
*/
54-
export async function deterministicUUID(key: string): Promise<string> {
54+
export async function deterministicUUID(
55+
key: string,
56+
priority = "normal"
57+
): Promise<string> {
5558
if (uuidCache.has(key)) {
5659
const uuid = uuidCache.get(key);
5760
if (typeof uuid === "string") {
@@ -61,6 +64,9 @@ export async function deterministicUUID(key: string): Promise<string> {
6164

6265
const encoder = new TextEncoder();
6366
const data = encoder.encode(key);
67+
if (priority === "low") {
68+
await waitForAnimationFrame();
69+
}
6470
// Usually under 1 ms; not outsourced to worker
6571
const hashBuffer = await crypto.subtle.digest("SHA-512", data);
6672
const hashHex = bufferToHex(hashBuffer);

0 commit comments

Comments
 (0)