-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Prerequisites
- I have searched the existing issues
- I understand that providing a SSCCE example is tremendously useful to the maintainers.
- I have read the documentation
- Ideally, I'm providing a sample JSFiddle, Codesandbox.io or preferably a shared playground link demonstrating the issue.
What theme are you using?
utils
Version
5.18.2
Current Behavior
The current implementation of isObject
from @rjsf/utils
is guaranteed to access at least one of the File
and Date
native classes for instanceof
checking. This incurs significant latency in the specific scenario where the a qiankun sub-application rerenders a Form component due to the combination of factors:
- High amount of
isObject
calls that each accessFile
andDate
classes - Small overhead incurred each time
File
orDate
is accessed due to qiankun's proxy sandbox.
For more context on how I discovered this issue, read the "Background" section
Expected Behavior
isObject
should be able to return early when it knows that the value cannot be a File
or Date
, which would greatly reduce the occasions that File
and Date
are accessed to only the times where objects that resemble a File
or Date
are passed into isObject
.
I've been exploring optimizing isObject
in this regard via this fork of RJSF.
Steps To Reproduce
Creating a sandbox example using RJSF within a qiankun sub-application is quite nontrivial, so for now, here's a playground demonstrating the number of accesses to File
and Date
made when updating a Form component: https://codesandbox.io/p/sandbox/react-jsonschema-form-forked-p3nspn
- Click on 'LoadData', which populates the
Form
component with new data - Notice how several hundred accesses to
File
andDate
are made on the spot despite the data having noFile
s orDate
s to speak of - Try modifying the form data before pressing 'LoadData' again
- Note how the number of accesses to
File
andDate
increased by a larger amount than before
Environment
- OS: Debian GNU/Linux 11 (bullseye)
- Node: v18.20.3
- npm: 9.8.1
- key packages:
- qiankun: 2.10.6
Anything else?
Background
The product I help develop uses the micro-frontend framework qiankun to run a React application providing multiple independent React sub-applications. To enforce isolation of these sub-application, qiankun provides proxy sandboxes that intercept accesses to globalThis
, window
, and other similar objects from the sub-applications.
When using a Form component with large schema within one sub-application, I quickly noticed that it took several hundred milliseconds overall for the UI to update after each letter typed, and so I started profiling performance via Chrome DevTools to investigate further.
Two primarily sources of overhead discovered are:
- Inefficient layout updates - my team is currently working to optimize this
- Rerendering of the Form component
Taking a deeper look at the second cause of overhead reveals a significant amount of self time coming from specific functions with RJSF and qiankun:
A significant portion of the total time of the Form rerendering task is devoted to isObject from @rjsf/utils
, which at first glance should be trivial to evaluate and have no impact on performance whatsoever. Diving deeper into the performance timeline reveals where the overhead comes from:
As it turns out, the "proxy sandbox" mentioned above intercepts accesses to any property of globalThis
, including File
and Date
, and the proxy's functions incur a small overhead (usually 0.15ms~0.5ms) each time such properties are accessed. This small overhead adds up very fast given the number of times isObject
is called whenever the Form component updates.