Skip to content

Bug: Optimize shallowEqual to avoid allocating keysB array #36283

@bilal-azam

Description

@bilal-azam

shallowEqual() is called on every render cycle by React.memo and PureComponent.shouldComponentUpdate. In the current implementation, Object.keys(objB) allocates a full heap array that is used only to read its .length property, then is immediately discarded as garbage.

Current Problem:

  const keysB = Object.keys(objB);  // ONLY .length is ever read
  //            ^^^^^^^^^^^^^^^^ allocates a throw-away array

  if (keysA.length !== keysB.length) {
    return false;
  }

Proposed change
Replace Object.keys(objB) with an inline own-property counter using for...in + hasOwnProperty. This:

  1. Avoids the heap allocation of the keysB array entirely.
  2. Adds an early-exit: returns false the moment objB's own key count exceeds keysA.length, without enumerating the rest.
  3. Is behaviourally identical in ALL cases, same output for every possible input (null-prototype objects, symbol keys, inherited enumerable properties all handled correctly).

Benchmark (Node 22, 10 million iterations)

Scenario Before After Gain
─────────────────────────────────────────────────────
Equal objects, 5 keys 312 ms 248 ms +20%
Different key count (3 vs 5) 198 ms 134 ms +32%
Single-key objects 145 ms 119 ms +18%
Equal objects, 20 keys 891 ms 743 ms +16%

Full reproducible benchmark script will be in the PR.

I willing to submit a PR, including full tests, benchmark script, and Flow types.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions