Skip to content

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

@Hsifnus

Description

@Hsifnus

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions