Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance hit from isObject when updating Form value within qiankun microapp #4409

Closed
4 tasks done
Hsifnus opened this issue Dec 4, 2024 · 1 comment · Fixed by #4413
Closed
4 tasks done

Performance hit from isObject when updating Form value within qiankun microapp #4409

Hsifnus opened this issue Dec 4, 2024 · 1 comment · Fixed by #4413

Comments

@Hsifnus
Copy link
Contributor

Hsifnus commented Dec 4, 2024

Prerequisites

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 access File and Date classes
  • Small overhead incurred each time File or Date 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

  1. Click on 'LoadData', which populates the Form component with new data
  2. Notice how several hundred accesses to File and Date are made on the spot despite the data having no Files or Dates to speak of
  3. Try modifying the form data before pressing 'LoadData' again
  4. Note how the number of accesses to File and Date 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.

Screenshot from 2024-12-04 18-56-30

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:

Screenshot from 2024-12-04 19-01-14

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:

Screenshot from 2024-12-04 18-58-38

Screenshot from 2024-12-04 19-09-45

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.

@Hsifnus Hsifnus added bug needs triage Initial label given, to be assigned correct labels and assigned labels Dec 4, 2024
@heath-freenome
Copy link
Member

@Hsifnus Wow, great analysis. If you believe that your optimization will not cause any regressions, we welcome PR. Please make sure to maintain 100% unit test coverage in the @rjsf/utils package. Thanks

@heath-freenome heath-freenome added help wanted and removed needs triage Initial label given, to be assigned correct labels and assigned labels Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants