GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Reject unrelated paths early in determineChangedProps by maoxor · Pull Request #4103 · plotly/dash

Conversation

@maoxor

@maoxor maoxor commented Oct 30, 2026

Copy link
Copy Markdown

Addresses #4032 (it makes this much cheaper, but it's still a scan, so I'm leaving the issue open for you to decide).

Components whose type sets dashChildrenUpdate (dcc.Tabs, and several DMC types) walk all of layoutHashes on every store update, and isFirstLevelPropsChild split both paths for each entry. As the issue says, the cost is flagged components x changed paths x store updates.

This keeps the scan and makes it cheap:

  • isFirstLevelPropsChild rejects unrelated paths with startsWith before splitting anything, and returns a shared constant for them.
  • determineChangedProps walks Object.keys instead of building an entry pair for each path.

The selector returns the same thing as before.

Numbers

I added a benchmark scenario, callback_fanout_children_update: one Input driving N Outputs with T dcc.Tabs mounted. Median of 3 runs of python -m benchmarks.run, production bundle, headless Chrome on an Apple Silicon Mac:

Outputs Tabs dev this PR
300 1 28.7 ms 28.1 ms
300 50 67.0 ms 32.9 ms
300 200 245.7 ms 58.7 ms
1000 1 231.4 ms 225.3 ms
1000 50 339.7 ms 244.8 ms
1000 200 787.7 ms 281.6 ms

For reference, callback_fanout (300 outputs, no Tabs) is about 30 ms on both. So with 300 outputs and 200 Tabs, the extra cost of the Tabs goes from about 216 ms to about 29 ms. The 1000 x 1 row comes from 4 rounds alternating the two builds, because my first pass ran dev first and showed a 4% difference that turned out to be run order.

In the profile of the new scenario, isFirstLevelPropsChild + determineChangedProps go from 51% of CPU to 9%. The rest of the suite stays within thresholds. I didn't touch baseline.json: it comes from CI hardware, so I'd rather not mix my laptop's numbers into it. Happy to change that if you prefer.

Why not an index

The issue suggests indexing layoutHashes by parent, so I tried it in a micro benchmark. One store update, with 1000 entries:

Flagged components current scan prefix check index rebuilt when layoutHashes changes
1 0.54 ms 0.06 ms 1.10 ms
50 24.7 ms 2.3 ms 1.05 ms
200 99.4 ms 10.6 ms 1.05 ms

A rebuilt index wins with many flagged components, but it's about twice as slow as today with a single dcc.Tabs, which I'd guess is the most common case. The prefix check is never slower and adds no state. An index kept up to date in the reducer could get the best of both, if the remaining cost still matters for apps like the one in the issue. I noted this in .ai/PERFORMANCE.md.

Testing

  • New tests/selectors.test.js: 5 tests through selectDashProps. They also pass on the old code, since behavior shouldn't change. The sibling case (...,4 vs ...,40) fails if the segment boundary check is removed.
  • Differential check (not committed): the old and new determineChangedProps side by side over 3000 random store histories, with nested flagged paths and removed entries. Identical on 284160 calls.
  • Renderer unit tests: 129 passed. test_descendant_listening, test_redraw, test_render_type and the dcc tab tests pass.
  • tests/integration/renderer: 88 passed, 3 failed. test_rdps015, 016 and 017 fail the same way on dev on my machine (the input isn't cleared before typing, so the text becomes initialedited), so they aren't related to this.

Contributor Checklist

  • I have broken down my PR scope into the following TODO tasks
    • Reject unrelated paths before allocating in isFirstLevelPropsChild
    • Add a benchmark scenario and unit tests
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR

optionals

  • I have added entry in the CHANGELOG.md

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
maoxor added 2 commits October 30, 2026 11:01
@maoxor
Reject unrelated paths early in determineChangedProps
fafd040
A component whose type sets dashChildrenUpdate (dcc.Tabs, several DMC
types) walks all of layoutHashes on every store update, and
isFirstLevelPropsChild split both paths for each entry. With many such
components mounted, this was the top of the CPU profile.

Check the path prefix with startsWith before allocating anything, and
walk the keys instead of building an entry pair for each one. The result
of the selector does not change.

Add a benchmark scenario for this case and unit tests for the selector.
@maoxor
Add CHANGELOG entry for plotly#4103
e6722d5
@sonarqubecloud

sonarqubecloud Bot commented Oct 30, 2026

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
0.0% Coverage on New Code
9.5% Duplication on New Code

See analysis details on SonarQube Cloud

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@T4rk1n T4rk1n mentioned this pull request Nov 6, 2026
Only reset descendant layout hashes when there is one to clear #4124
Open
4 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@maoxor
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.