feat: improve initial load performance on mobile (#2126)
This commit is contained in:
@@ -21,6 +21,8 @@ import {
|
||||
DecryptedItem,
|
||||
EditorIdentifier,
|
||||
FeatureIdentifier,
|
||||
Environment,
|
||||
ApplicationOptionsDefaults,
|
||||
} from '@standardnotes/snjs'
|
||||
import { makeObservable, observable } from 'mobx'
|
||||
import { PanelResizedData } from '@/Types/PanelResizedData'
|
||||
@@ -75,6 +77,8 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
defaultHost: defaultSyncServerHost,
|
||||
appVersion: deviceInterface.appVersion,
|
||||
webSocketUrl: webSocketUrl,
|
||||
loadBatchSize:
|
||||
deviceInterface.environment === Environment.Mobile ? 100 : ApplicationOptionsDefaults.loadBatchSize,
|
||||
})
|
||||
|
||||
makeObservable(this, {
|
||||
|
||||
@@ -140,6 +140,39 @@ export class Database {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is actually unused, but implemented to conform to protocol in case it is eventually needed.
|
||||
* We could remove implementation and throw instead, but it might be better to offer a functional alternative instead.
|
||||
*/
|
||||
public async getPayloadsForKeys(keys: string[]): Promise<any[]> {
|
||||
const db = (await this.openDatabase()) as IDBDatabase
|
||||
return new Promise((resolve) => {
|
||||
const objectStore = db.transaction(STORE_NAME).objectStore(STORE_NAME)
|
||||
const payloads: any = []
|
||||
let numComplete = 0
|
||||
for (const key of keys) {
|
||||
const getRequest = objectStore.get(key)
|
||||
getRequest.onsuccess = (event) => {
|
||||
const target = event.target as any
|
||||
const result = target.result
|
||||
if (result) {
|
||||
payloads.push(result)
|
||||
}
|
||||
numComplete++
|
||||
if (numComplete === keys.length) {
|
||||
resolve(payloads)
|
||||
}
|
||||
}
|
||||
getRequest.onerror = () => {
|
||||
numComplete++
|
||||
if (numComplete === keys.length) {
|
||||
resolve(payloads)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public async getAllKeys(): Promise<string[]> {
|
||||
const db = (await this.openDatabase()) as IDBDatabase
|
||||
|
||||
|
||||
@@ -2,13 +2,16 @@ import {
|
||||
SNApplication,
|
||||
ApplicationIdentifier,
|
||||
Environment,
|
||||
LegacyRawKeychainValue,
|
||||
RawKeychainValue,
|
||||
TransferPayload,
|
||||
NamespacedRootKeyInKeychain,
|
||||
extendArray,
|
||||
WebOrDesktopDeviceInterface,
|
||||
Platform,
|
||||
FullyFormedTransferPayload,
|
||||
DatabaseLoadOptions,
|
||||
GetSortedPayloadsByPriority,
|
||||
DatabaseFullEntryLoadChunk,
|
||||
DatabaseFullEntryLoadChunkResponse,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Database } from '../Database'
|
||||
|
||||
@@ -72,17 +75,6 @@ export abstract class WebOrDesktopDevice implements WebOrDesktopDeviceInterface
|
||||
return result
|
||||
}
|
||||
|
||||
async getAllRawStorageKeyValues() {
|
||||
const results = []
|
||||
for (const key of Object.keys(localStorage)) {
|
||||
results.push({
|
||||
key: key,
|
||||
value: localStorage[key],
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
async setRawStorageValue(key: string, value: string) {
|
||||
localStorage.setItem(key, value)
|
||||
}
|
||||
@@ -111,23 +103,63 @@ export abstract class WebOrDesktopDevice implements WebOrDesktopDeviceInterface
|
||||
}) as Promise<{ isNewDatabase?: boolean } | undefined>
|
||||
}
|
||||
|
||||
async getAllRawDatabasePayloads(identifier: ApplicationIdentifier) {
|
||||
async getDatabaseLoadChunks(
|
||||
options: DatabaseLoadOptions,
|
||||
identifier: string,
|
||||
): Promise<DatabaseFullEntryLoadChunkResponse> {
|
||||
const entries = await this.getAllDatabaseEntries(identifier)
|
||||
const sorted = GetSortedPayloadsByPriority(entries, options)
|
||||
|
||||
const itemsKeysChunk: DatabaseFullEntryLoadChunk = {
|
||||
entries: sorted.itemsKeyPayloads,
|
||||
}
|
||||
|
||||
const contentTypePriorityChunk: DatabaseFullEntryLoadChunk = {
|
||||
entries: sorted.contentTypePriorityPayloads,
|
||||
}
|
||||
|
||||
const remainingPayloadsChunks: DatabaseFullEntryLoadChunk[] = []
|
||||
for (let i = 0; i < sorted.remainingPayloads.length; i += options.batchSize) {
|
||||
remainingPayloadsChunks.push({
|
||||
entries: sorted.remainingPayloads.slice(i, i + options.batchSize),
|
||||
})
|
||||
}
|
||||
|
||||
const result: DatabaseFullEntryLoadChunkResponse = {
|
||||
fullEntries: {
|
||||
itemsKeys: itemsKeysChunk,
|
||||
remainingChunks: [contentTypePriorityChunk, ...remainingPayloadsChunks],
|
||||
},
|
||||
remainingChunksItemCount: sorted.contentTypePriorityPayloads.length + sorted.remainingPayloads.length,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async getAllDatabaseEntries(identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).getAllPayloads()
|
||||
}
|
||||
|
||||
async saveRawDatabasePayload(payload: TransferPayload, identifier: ApplicationIdentifier) {
|
||||
getDatabaseEntries<T extends FullyFormedTransferPayload = FullyFormedTransferPayload>(
|
||||
identifier: string,
|
||||
keys: string[],
|
||||
): Promise<T[]> {
|
||||
return this.databaseForIdentifier(identifier).getPayloadsForKeys(keys)
|
||||
}
|
||||
|
||||
async saveDatabaseEntry(payload: TransferPayload, identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).savePayload(payload)
|
||||
}
|
||||
|
||||
async saveRawDatabasePayloads(payloads: TransferPayload[], identifier: ApplicationIdentifier) {
|
||||
async saveDatabaseEntries(payloads: TransferPayload[], identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).savePayloads(payloads)
|
||||
}
|
||||
|
||||
async removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier) {
|
||||
async removeDatabaseEntry(id: string, identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).deletePayload(id)
|
||||
}
|
||||
|
||||
async removeAllRawDatabasePayloads(identifier: ApplicationIdentifier) {
|
||||
async removeAllDatabaseEntries(identifier: ApplicationIdentifier) {
|
||||
return this.databaseForIdentifier(identifier).clearAllPayloads()
|
||||
}
|
||||
|
||||
@@ -141,16 +173,6 @@ export abstract class WebOrDesktopDevice implements WebOrDesktopDeviceInterface
|
||||
return keychain[identifier]
|
||||
}
|
||||
|
||||
async getDatabaseKeys(): Promise<string[]> {
|
||||
const keys: string[] = []
|
||||
|
||||
for (const database of this.databases) {
|
||||
extendArray(keys, await database.getAllKeys())
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
async setNamespacedKeychainValue(value: NamespacedRootKeyInKeychain, identifier: ApplicationIdentifier) {
|
||||
let keychain = await this.getKeychainValue()
|
||||
|
||||
@@ -186,10 +208,6 @@ export abstract class WebOrDesktopDevice implements WebOrDesktopDeviceInterface
|
||||
}
|
||||
}
|
||||
|
||||
setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void> {
|
||||
return this.setKeychainValue(value)
|
||||
}
|
||||
|
||||
abstract getKeychainValue(): Promise<RawKeychainValue>
|
||||
|
||||
abstract setKeychainValue(value: unknown): Promise<void>
|
||||
|
||||
Reference in New Issue
Block a user