realm-js
realm-js copied to clipboard
React Native: UI is unresponsive while inserting objects
Hi!
I'm currently working on a React Native app using Realm JS which has been in production for a while now. So far everything has been working fine, however I've noticed that sometimes the UI is completely unresponsive while an insert transaction is being executed (both develop and production builds). This usually happens with large amounts of data, although I've also experienced this with as little as 50 records.
The app fetches a considerable amount of data when it first starts, this data is then stored and encrypted using Realm. The unresponsiveness can be between 2s up to 30 seconds! In the worst case users cannot do anything until Realm is done with the transaction, which can be irritating for them.
The data models being stored don't have a particularly large number of properties. The sample repository I provide below contains sample data which resembles what's used in reality.
Any tips on how to avoid this would be very helpful. I've searched around an tried multiple approaches with no luck. I've even tried libraries such as this: https://github.com/joltup/react-native-threads but they sometimes don't even compile or cause additional issues to my app.
Goals
Users should be able to navigate freely and use the app normally while Realm is executing a transaction.
Expected Results
The UI shouldn't freeze. Navigation and general app functionality should function normally.
Actual Results
The UI freezes, sometimes for noticeable long periods of time, until Realm is done inserting all records. As users need to access more data the issue becomes more noticeable and frustrating.
Steps to Reproduce
Simply running an insert transaction as follows:
realm.write(() => { sampleModels.forEach(model => { realm.create(Schema.name, model, UpdateMode.All); }); });
The problem is worse the more data records are inserted.
Code Sample
I have created a very simple React Native project which showcases the issue:
https://github.com/MHV1/RealmPerformanceIssue
The issue can be observed when pressing a button which will trigger the Realm transactions. The button animation will freeze. Attempting to press the additional button in the app while the transaction is in progress will cause no response whatsoever.
The amount of data being inserted is similar to that in the real app.
Version of Realm and Tooling
- Realm JS SDK Version: 10.4.0
- Node or React Native: React Native 0.64.0
- Client OS & Version: both iOS and Android, no specific version
- Which debugger for React Native: None
Most likely realm is 100% sync (no bridge) so while realm is running, JS/Native is fully blocked. Your only option is to batch expensive operations in timeouts I think.
You can try small transactions:
sampleModels.forEach(model => {
realm.write(() => {
realm.create(Schema.name, model, UpdateMode.All);
});
});
Currently Realm doesn't support multi-processes, and despite the name react-native-threads utilitizes multiple processes and not threads.
@kneth I did try that approach, however the performance is considerably worse, specially if we talk thousands of records.
For instance in the sample project I provided having a large number of realm.write blocks will freeze the UI for several minutes (70000+ records). So in this case a big transaction still seems to be the way to go. Also this makes sense after having a look at these issues with similar scenarios: https://github.com/realm/realm-js/issues/1002 https://github.com/realm/realm-js/issues/2499
I'm yet to try smaller batches as @cristianoccazinsp suggests, although I'm curious to see if this would indeed ease the UI thread load without taking longer to persist all the data.
Anyway, thanks your help so far! I'll try to find other approaches. Will leave this open for now and see if there's any other suggestions.
one thing that seems to unblock the ui is running realm writes inside requestAnimationFrame,
one write per frame could take a while to complete, but ui stays interactable
edit: performance now seems better using one write transaction in one requestAnimationFrame and looping over all writes, instead of over multiple frames note: not using the hermes branch
I am finding that simply creating a write transaction without inserting any objects takes ~20ms. This seems totally unacceptable, is this to be expected? @kneth (Tested on 10.20.0-beta.1 and 10.20.0-beta.5).
@mfbx9da4 That is not expected, though it could be related to the performance regressions in the Hermes branch (#4443). I'll see if I can reproduce that here. Is the UI also unresponsive during this 20ms?
Well the JS thread is blocked because write transactions are synchronous so yes, all UI interactions which require JS are blocked during that time. The main UI thread is free so I'm able to scroll around but any meaningful interaction is blocked.
Cool, I was just checking that this ticket was the right place for the report. I'll try to repro and let you know how it goes. It might be that we move this to the Hermes performance regression issue if that seems to be the culprit in your case.
Likely @hugo-chq workaround is not actually "unblock"ing the UI but rather deferring the blocking of the UI.
Unfortunately I have to use the hermes branch @tomduncalf because I am affected by this issue https://github.com/realm/realm-js/issues/3837
@mfbx9da4 We're actively working to resolve the Hermes performance regressions. The ticket has more details, with Hermes enabled the regression is caused by internal Hermes code which times every call across the C++/JS boundary so we are waiting on a new RN release from Meta, with Hermes disabled the regression is on our side so we are looking at ways to mitigate that.
Just to let you know I was able to confirm your findings @mfbx9da4, I see a transaction take ~20ms on our Hermes branch (with Hermes disabled) and ~1/2ms on our master branch. I suspect the root cause is the same as the other performance regressions (the new method for accessing the internal C++ objects is slower). I'll update you when we have something for you to try to resolve this.
@kneth any solution on new realm v12?
the UI is crashing because of data entry I'm inserting every 1000 records (total 100k+), but it's still blocking the UI.
Did I think of any multi thread alternatives?
What does it mean for the UI to be crashing? Do you yield the thread between insertions to allow for the UI to render? And how long does a single batch of 1000 documents take and on which device do you measure it?