Skip to content
Closed
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
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-05-18 - Avoid redundant JSON parsing in wasmJs LocalStorage caching
**Learning:** In the `wasmJs` target, the `LocalStorageThemeCache` previously parsed the JSON manifest array from `localStorage` on every operation (e.g. `size()`, `keys()`, `put()`, `evict()`), which is very expensive when done repeatedly. Caching the manifest array in memory significantly reduces overhead while still maintaining correctness for concurrent UI operations within a single session.
**Action:** Always consider the cost of JSON parsing in browser environments, particularly for frequently accessed metadata. Add a lightweight in-memory caching layer on top of `localStorage` to memoize the deserialized state when it is safe to do so within the bounds of a single user session.
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,27 @@ public class LocalStorageThemeCache(
private val _changes = MutableSharedFlow<CacheEvent>(extraBufferCapacity = 64)
private val json = Json { ignoreUnknownKeys = true }
private val manifestKey = "${prefix}__keys__"
private var manifestCache: MutableSet<String>? = null

// ── Manifest helpers ────────────────────────────────────────────────

private fun readManifest(): MutableSet<String> {
manifestCache?.let { return it.toMutableSet() }

val raw = jsGetItem(manifestKey.toJsString())?.toString() ?: return mutableSetOf()
return try {
val parsed = try {
json.decodeFromString<Set<String>>(raw).toMutableSet()
} catch (_: Exception) {
mutableSetOf()
}
manifestCache = parsed.toMutableSet()
return parsed
}

private fun writeManifest(keys: Set<String>) {
val encoded = json.encodeToString(keys)
jsSetItem(manifestKey.toJsString(), encoded.toJsString())
manifestCache = keys.toMutableSet()
}

// ── Entry helpers ───────────────────────────────────────────────────
Expand Down Expand Up @@ -155,6 +161,7 @@ public class LocalStorageThemeCache(
removeEntry("$prefix$key")
}
jsRemoveItem(manifestKey.toJsString())
manifestCache = null
_changes.tryEmit(CacheEvent.Cleared)
}

Expand Down
Loading