Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

kfule
Copy link
Contributor

@kfule kfule commented Oct 6, 2025

Improves Vnode.normalizeChildren() performance by avoiding array re-creation, merging loops, reducing comparisons, and performing key consistency checks after normalization without breaking existing behavior.

Description

This change improves the performance of Vnode.normalizeChildren() by:

  • avoiding unnecessary array re-creation
    • set a flag on the children of the component vnode for array re-creation
    • Since vnode objects are reused as-is during normalization, I believe array reuse itself is also acceptable.
      • Furthermore, in-place normalization is the same as v1.
  • optimizing loops and consistency checks
    • check consistency by counting the number of keyed vnodes after normalization

result of npm run perf

npm run perf (on my laptop, node v22) #3041 (ops/sec) this PR (ops/sec) Performance Gain
construct large vnode tree 25,949 29,585 +14.0%
rerender identical vnode 4,677,364 5,031,685 +7.6%
rerender same tree 100,954 105,471 +4.5%
rerender same tree (with selector-generated attrs) 131,815 143,874 +9.1%
add large nested tree 8,277 8,647 +4.5%
mutate styles/properties 139 149 +7.2%
repeated add/removal 2,949 2,987 +1.3%

Based on the results of #3041, this change improves performance by about 5% for "rerender same tree".

Motivation and Context

Earlier, I found that performance could be improved by avoiding array re-creation and removing consistency checks, as in v1.
However, that approach clearly broke the current behavior, so I did not include it in #3041.

After further investigation, it turned out that similar performance improvements could be achieved without breaking the current behavior.

Although I’m slightly disappointed by the small increase in bundle size introduced in this PR after #3050, I’m pleased with the noticeable performance improvements.

How Has This Been Tested?

npm run test

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My change requires a documentation update, and I've opened a pull request to update it already:
  • I have read https://mithril.js.org/contributing.html.

kfule added 2 commits October 6, 2025 19:00
…nodes are not component vnodes

Since commit 1579fe8, all `vnode.children` arrays have been recreated during normalization. However, for non-component vnodes, creating new arrays is unnecessary. This change normalizes them in place to improve performance.

Passes all existing tests as is.
… for better performance

This change merges multiple loops into a single one and reduces the number of comparisons needed for consistency checking, resulting in improved performance.
Additionally, since key checks are now performed on normalized vnodes, the consistency checks become more accurate.
All existing tests pass.

The comments have also been clarified with reference to the original commit 6c562d2.
@kfule kfule requested a review from a team as a code owner October 6, 2025 11:30
@dead-claudia
Copy link
Member

Unfortunately, removing the array cloning is a breaking change. People actually depend on that behavior, depending on Mithril to not change nodes out from under them before they're returned to the renderer.

@dead-claudia dead-claudia added Type: Breaking Change For any feature request or suggestion that could reasonably break existing code Area: Core For anything dealing with Mithril core itself major labels Oct 9, 2025
@kfule
Copy link
Contributor Author

kfule commented Oct 9, 2025

@dead-claudia Thank you very much for your review.
I personally think the idea is good, but I wouldn’t like this to be treated as a major or breaking change.

It seems that array cloning is the main bottleneck, so optimizing only loops and integrity checks doesn’t provide much performance improvement.
Therefore, I’ve decided to close this PR.

Thanks again for taking the time to review it!

@kfule kfule closed this Oct 9, 2025
@dead-claudia
Copy link
Member

I personally think the idea is good, but I wouldn’t like this to be treated as a major or breaking change.

@kfule In an ideal world, I would agree with you, but unfortunately, it's just too risky. People have long been directly mutating the vnode arrays they return. I've seen it multiple times in issues and discussions through the years, complete with people wondering why they can't .sort() vnode arrays and expect it to work. (I wish I was joking...)

@kfule
Copy link
Contributor Author

kfule commented Oct 9, 2025

@dead-claudia You're right - there are all kinds of users out there, so this change could indeed be too risky😅

@kfule kfule mentioned this pull request Oct 12, 2025
8 tasks
@kfule
Copy link
Contributor Author

kfule commented Oct 12, 2025

@dead-claudia I've made a new finding and created a separate PR instead of reopening this PR. The new PR is more modest than this PR, but I believe it is a non-breaking improvement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Core For anything dealing with Mithril core itself major Type: Breaking Change For any feature request or suggestion that could reasonably break existing code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.