App: [Performance] localforage.setItem() is causing blocking behavior on init for web clients
Creating this in E/App repo from this issue in the E/react-native-onyx repo, in case an external contributor can work on it.
Problem
When the app inits and many keys need to be set things get really slow on web. It currently takes me about 10-12 seconds to switch to a new chat when the app inits.
We’ve narrowed down the source of the problem to:
- Not stringifying IndexedDB values. For whatever reason IDB takes a while to store structured JSON.
- Calling
setItem()too many times in a row
Addressing either one should work. Both seem to be causing similar rates of pain.
Solution
- Start stringifying values - complicated because some of the JSON is not serializable i.e. stuff with attachments.
- Defer the writing to IndexedDB until we are idle or just slow it down or something at least. We are using a memory cache already so I can’t think of a reason why our writes must happen immediately on page load.
More ideas here: https://rxdb.info/slow-indexeddb.html, but the general suggestion is to use fewer transactions. That is not possible with localforage so we might want to look elsewhere - maybe the plugin mentioned here can help https://github.com/localForage/localForage/issues/315
I did a test here where I just made all the writes synchronous (probably not the solution we want), but it improves things immensely
https://github.com/Expensify/react-native-onyx/pull/118
cc @marcaaron
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 21 (14 by maintainers)
Possibly related, I’d like to try to test after this issue is fixed to see if can reproduce
@dylanexpensify , I posted the job since I was back in here…
https://www.upwork.com/jobs/~01d8bffdd4e6f23ff8
a fix should be on staging soon.
Linked PRs to fix this are not merged yet so gonna reopen this and assign myself.
For this specific storage provider (WebStorage) any Onyx write operation (
set,mergeormergeCollection) is applied throughsetItemWe’ve decided to batch
Whenever we write something with Onyx we first write the change to cache App is free to read anything anytime and then use it to write something new App would read (though Onyx) the latest data from cache - this should cover the case where a new value depends on existing value
Batches would apply changes in FIFO, so if a batch captures multiple updates for the same key, the last update would overwrite previous. (We can further optimize this to just use the latest key if necessary)
The way we requeue the failed keys is that we insert them in the begging of the next batch and then start the next batch. This would ensure they get overwritten if there are newer changes for these keys So we shouldn’t be blocked
It might turn out that the SyncQueue implemented in @marcaaron PR is completely satisfying performance and there’s no need for all of this
Alright, I tried to wrap my head around this but I just have a lot of (basic) questions which I’ll post later. @thienlnam please take over this issue. I’m just gonna watch and learn, and ofc ask questions 😃
cc: @parasharrajat / @Santhosh-Sellavel if you’re interested in reviewing this.
Reassigning C+ to @rushatgabhane , @Santhosh-Sellavel is starting this/next week @kidroca , can you please look into? For a fix or to help with a fix