diff --git a/package-lock.json b/package-lock.json index 2cb316f..2d02aa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5590,6 +5590,11 @@ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=" + }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", diff --git a/package.json b/package.json index 1fa54ed..b51a2d2 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "npm-run-all": "^4.1.2", "performance-now": "^2.1.0", "pify": "^3.0.0", + "quick-lru": "^1.1.0", "requestidlecallback": "^0.3.0", "rimraf": "^2.6.2", "sapper": "^0.3.2", diff --git a/routes/_components/Timeline.html b/routes/_components/Timeline.html index 2b43f17..bf59344 100644 --- a/routes/_components/Timeline.html +++ b/routes/_components/Timeline.html @@ -1,7 +1,8 @@ <:Window bind:online />
({ StatusListItem: StatusListItem, LoadingFooter: LoadingFooter, - statuses: [], + statusIds: [], runningUpdate: false, initialized: false }), computed: { - keyedStatuses: (statuses) => statuses.map(status => ({ - props: status, - key: status.id - })), - lastStatusId: (statuses) => statuses.length && statuses[statuses.length - 1].id, + makeProps: ($currentInstance) => (statusId) => database.getStatus($currentInstance, statusId), + items: (statusIds) => { + return statusIds.map(statusId => ({ + key: statusId + })) + }, + lastStatusId: (statusIds) => statusIds.length && statusIds[statusIds.length - 1], label: (timeline, $currentInstance) => { if (timelines[timeline]) { `${timelines[timeline].label} timeline for ${$currentInstance}` @@ -89,12 +92,16 @@ if (process.env.NODE_ENV !== 'production') { console.log('addStatuses()') } - let statuses = this.get('statuses') - if (!statuses) { + let instanceName = this.store.get('instanceName') + let timeline = this.get('timeline') + /* no await */ database.insertStatuses(instanceName, timeline, newStatuses) + let statusIds = this.get('statusIds') + if (!statusIds) { return } - let merged = mergeStatuses(statuses, newStatuses) - this.set({ statuses: merged }) + let newStatusIds = newStatuses.map(status => status.id) + let merged = mergeStatuses(statusIds, newStatusIds) + this.set({ statusIds: merged }) }, async fetchStatusesAndPossiblyFallBack() { let online = this.get('online') diff --git a/routes/_components/VirtualList.html b/routes/_components/VirtualList.html index 1d8c311..fcc694a 100644 --- a/routes/_components/VirtualList.html +++ b/routes/_components/VirtualList.html @@ -1,11 +1,11 @@
{{#each $visibleItems as item @key}} - {{/each}} {{#if $showFooter}} @@ -19,7 +19,7 @@ } \ No newline at end of file diff --git a/routes/_utils/database/databaseCore.js b/routes/_utils/database/databaseCore.js index 0f531aa..7a07bc2 100644 --- a/routes/_utils/database/databaseCore.js +++ b/routes/_utils/database/databaseCore.js @@ -13,6 +13,18 @@ import { STATUSES_STORE, ACCOUNTS_STORE } from './constants' +import QuickLRU from 'quick-lru' + +const statusesCache = new QuickLRU({maxSize: 100}) + +if (process.browser && process.env.NODE_ENV !== 'production') { + window.cacheStats = { + cache: statusesCache, + cacheHits: 0, + cacheMisses: 0 + } +} + export async function getTimeline(instanceName, timeline, maxId = null, limit = 20) { const db = await getDatabase(instanceName, timeline) return await dbPromise(db, [TIMELINE_STORE, STATUSES_STORE], 'readonly', (stores, callback) => { @@ -37,6 +49,9 @@ export async function getTimeline(instanceName, timeline, maxId = null, limit = } export async function insertStatuses(instanceName, timeline, statuses) { + for (let status of statuses) { + statusesCache.set(status.id, status) + } const db = await getDatabase(instanceName, timeline) await dbPromise(db, [TIMELINE_STORE, STATUSES_STORE, ACCOUNTS_STORE], 'readwrite', (stores) => { let [ timelineStore, statusesStore, accountsStore ] = stores @@ -85,4 +100,24 @@ export async function getAccount(instanceName, accountId) { export async function clearDatabaseForInstance(instanceName) { await deleteDatabase(instanceName) +} + +export async function getStatus(instanceName, statusId) { + if (statusesCache.has(statusId)) { + if (process.browser && process.env.NODE_ENV !== 'production') { + window.cacheStats.cacheHits++ + } + return statusesCache.get(statusId) + } + const db = await getDatabase(instanceName) + let result = await dbPromise(db, STATUSES_STORE, 'readonly', (store, callback) => { + store.get(statusId).onsuccess = (e) => { + callback(e.target.result && e.target.result) + } + }) + statusesCache.set(statusId, result) + if (process.browser && process.env.NODE_ENV !== 'production') { + window.cacheStats.cacheMisses++ + } + return result } \ No newline at end of file diff --git a/routes/_utils/statuses.js b/routes/_utils/statuses.js index 9365455..0586847 100644 --- a/routes/_utils/statuses.js +++ b/routes/_utils/statuses.js @@ -1,27 +1,26 @@ // Merge two lists of statuses for the same timeline, e.g. one from IDB // and another from the network. In case of duplicates, prefer the fresh. -export function mergeStatuses(leftStatuses, rightStatuses) { +export function mergeStatuses(leftStatusIds, rightStatusIds) { let leftIndex = 0 let rightIndex = 0 let merged = [] - while (leftIndex < leftStatuses.length || rightIndex < rightStatuses.length) { - if (leftIndex === leftStatuses.length) { - merged.push(rightStatuses[rightIndex]) + while (leftIndex < leftStatusIds.length || rightIndex < rightStatusIds.length) { + if (leftIndex === leftStatusIds.length) { + merged.push(rightStatusIds[rightIndex]) rightIndex++ continue } - if (rightIndex === rightStatuses.length) { - merged.push(leftStatuses[leftIndex]) + if (rightIndex === rightStatusIds.length) { + merged.push(leftStatusIds[leftIndex]) leftIndex++ continue } - let left = leftStatuses[leftIndex] - let right = rightStatuses[rightIndex] - if (right.id === left.id) { - merged.push(right.pinafore_stale ? left : right) + let left = leftStatusIds[leftIndex] + let right = rightStatusIds[rightIndex] + if (right === left) { rightIndex++ leftIndex++ - } else if (parseInt(right.id, 10) > parseInt(left.id, 10)) { + } else if (parseInt(right, 10) > parseInt(left, 10)) { merged.push(right) rightIndex++ } else { diff --git a/routes/_utils/virtualListStore.js b/routes/_utils/virtualListStore.js index 32b7ea7..8d02c35 100644 --- a/routes/_utils/virtualListStore.js +++ b/routes/_utils/virtualListStore.js @@ -56,7 +56,7 @@ virtualListStore.compute('visibleItems', let len = items.length let i = -1 while (++i < len) { - let { props, key } = items[i] + let { key } = items[i] let height = itemHeights[key] || 0 let currentOffset = totalOffset totalOffset += height @@ -72,7 +72,6 @@ virtualListStore.compute('visibleItems', } visibleItems.push({ offset: currentOffset, - props: props, key: key, index: i })