* Introduce an image sizes cache to improve feed layouts (close #213) * Clear out resolved promises from the image cache
This commit is contained in:
parent
c1d454b7cf
commit
858d4c8c88
7 changed files with 92 additions and 30 deletions
37
src/state/models/cache/image-sizes.ts
vendored
Normal file
37
src/state/models/cache/image-sizes.ts
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
import {Image} from 'react-native'
|
||||
import {Dim} from 'lib/media/manip'
|
||||
|
||||
export class ImageSizesCache {
|
||||
sizes: Map<string, Dim> = new Map()
|
||||
private activeRequests: Map<string, Promise<Dim>> = new Map()
|
||||
|
||||
constructor() {}
|
||||
|
||||
get(uri: string): Dim | undefined {
|
||||
return this.sizes.get(uri)
|
||||
}
|
||||
|
||||
async fetch(uri: string): Promise<Dim> {
|
||||
const dim = this.sizes.get(uri)
|
||||
if (dim) {
|
||||
return dim
|
||||
}
|
||||
const prom =
|
||||
this.activeRequests.get(uri) ||
|
||||
new Promise<Dim>(resolve => {
|
||||
Image.getSize(
|
||||
uri,
|
||||
(width: number, height: number) => resolve({width, height}),
|
||||
(err: any) => {
|
||||
console.error('Failed to fetch image dimensions for', uri, err)
|
||||
resolve({width: 0, height: 0})
|
||||
},
|
||||
)
|
||||
})
|
||||
this.activeRequests.set(uri, prom)
|
||||
const res = await prom
|
||||
this.activeRequests.delete(uri)
|
||||
this.sizes.set(uri, res)
|
||||
return res
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {LRUMap} from 'lru_map'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {LinkMeta, getLinkMeta} from 'lib/link-meta/link-meta'
|
||||
|
||||
type CacheValue = Promise<LinkMeta> | LinkMeta
|
||||
export class LinkMetasViewModel {
|
||||
export class LinkMetasCache {
|
||||
cache: LRUMap<string, CacheValue> = new LRUMap(100)
|
||||
|
||||
constructor(public rootStore: RootStoreModel) {
|
|
@ -1,6 +1,6 @@
|
|||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {FollowRecord, AppBskyActorProfile, AppBskyActorRef} from '@atproto/api'
|
||||
import {RootStoreModel} from './root-store'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {bundleAsync} from 'lib/async/bundle'
|
||||
|
||||
const CACHE_TTL = 1000 * 60 * 60 // hourly
|
||||
|
@ -16,7 +16,7 @@ type Profile =
|
|||
* follows. It should be periodically refreshed and updated any time
|
||||
* the user makes a change to their follows.
|
||||
*/
|
||||
export class MyFollowsModel {
|
||||
export class MyFollowsCache {
|
||||
// data
|
||||
followDidToRecordMap: Record<string, string> = {}
|
||||
lastSync = 0
|
|
@ -2,7 +2,7 @@ import {makeAutoObservable, runInAction} from 'mobx'
|
|||
import {RootStoreModel} from './root-store'
|
||||
import {FeedModel} from './feed-view'
|
||||
import {NotificationsViewModel} from './notifications-view'
|
||||
import {MyFollowsModel} from './my-follows'
|
||||
import {MyFollowsCache} from './cache/my-follows'
|
||||
import {isObj, hasProp} from 'lib/type-guards'
|
||||
|
||||
export class MeModel {
|
||||
|
@ -15,7 +15,7 @@ export class MeModel {
|
|||
followersCount: number | undefined
|
||||
mainFeed: FeedModel
|
||||
notifications: NotificationsViewModel
|
||||
follows: MyFollowsModel
|
||||
follows: MyFollowsCache
|
||||
|
||||
constructor(public rootStore: RootStoreModel) {
|
||||
makeAutoObservable(
|
||||
|
@ -27,7 +27,7 @@ export class MeModel {
|
|||
algorithm: 'reverse-chronological',
|
||||
})
|
||||
this.notifications = new NotificationsViewModel(this.rootStore, {})
|
||||
this.follows = new MyFollowsModel(this.rootStore)
|
||||
this.follows = new MyFollowsCache(this.rootStore)
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
|
|
@ -13,10 +13,11 @@ import {LogModel} from './log'
|
|||
import {SessionModel} from './session'
|
||||
import {ShellUiModel} from './ui/shell'
|
||||
import {ProfilesViewModel} from './profiles-view'
|
||||
import {LinkMetasViewModel} from './link-metas-view'
|
||||
import {LinkMetasCache} from './cache/link-metas'
|
||||
import {NotificationsViewItemModel} from './notifications-view'
|
||||
import {MeModel} from './me'
|
||||
import {resetToTab} from '../../Navigation'
|
||||
import {ImageSizesCache} from './cache/image-sizes'
|
||||
|
||||
export const appInfo = z.object({
|
||||
build: z.string(),
|
||||
|
@ -34,7 +35,8 @@ export class RootStoreModel {
|
|||
shell = new ShellUiModel(this)
|
||||
me = new MeModel(this)
|
||||
profiles = new ProfilesViewModel(this)
|
||||
linkMetas = new LinkMetasViewModel(this)
|
||||
linkMetas = new LinkMetasCache(this)
|
||||
imageSizes = new ImageSizesCache()
|
||||
|
||||
// HACK
|
||||
// this flag is to track the lexicon breaking refactor
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue