Skip to content

Improve hooks performance with a cold unmount queue - #5202

Closed
JoviDeCroock wants to merge 1 commit into
mainfrom
perf/cold-unmount-queue
Closed

Improve hooks performance with a cold unmount queue#5202
JoviDeCroock wants to merge 1 commit into
mainfrom
perf/cold-unmount-queue

Conversation

@JoviDeCroock

@JoviDeCroock JoviDeCroock commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

  • store the deferred passive-unmount queue on the after-paint flush function instead of in a mutable module-level binding
  • pin the affected private hook property mangles so production output remains deterministic

This preserves passive cleanup ordering and deferred error routing while reducing the aggregate overhead measured in the Preact 11 hook paths.

Performance

Paired production Chromium runs against the previous Preact 11 build:

Octane suite Geomean
js-framework 8.0% faster
memo-wall 11.4% faster
effectful-list 1.9% slower

All exact Octane correctness gates passed. The result is mixed at the individual-operation level: js-framework run and replace were 7.1% and 10.5% slower, while update/select/reorder/removal paths drove the aggregate improvement. The effectful-list result was mostly neutral, with remove_100_scattered 8.3% slower.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

📊 Tachometer Benchmark Results

Summary

duration

  • create10k: unsure 🔍 -0% - +1% (-1.19ms - +5.88ms)
    preact-local vs preact-main
  • filter-list: unsure 🔍 -0% - +1% (-0.02ms - +0.17ms)
    preact-local vs preact-main
  • hydrate1k: unsure 🔍 -1% - +3% (-0.25ms - +1.26ms)
    preact-local vs preact-main
  • many-updates: unsure 🔍 -2% - +2% (-0.28ms - +0.38ms)
    preact-local vs preact-main
  • replace1k: unsure 🔍 -1% - +2% (-0.55ms - +1.27ms)
    preact-local vs preact-main
  • text-update: unsure 🔍 -4% - +4% (-0.08ms - +0.07ms)
    preact-local vs preact-main
  • todo: unsure 🔍 -2% - +1% (-0.52ms - +0.23ms)
    preact-local vs preact-main
  • update10th1k: unsure 🔍 -5% - +3% (-2.04ms - +1.34ms)
    preact-local vs preact-main

usedJSHeapSize

  • create10k: unsure 🔍 -0% - +0% (-0.04ms - +0.02ms)
    preact-local vs preact-main
  • filter-list: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • hydrate1k: unsure 🔍 -2% - +3% (-0.09ms - +0.15ms)
    preact-local vs preact-main
  • many-updates: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • replace1k: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • text-update: unsure 🔍 -2% - +5% (-0.02ms - +0.05ms)
    preact-local vs preact-main
  • todo: unsure 🔍 -0% - +0% (-0.00ms - +0.00ms)
    preact-local vs preact-main
  • update10th1k: unsure 🔍 -0% - +0% (-0.01ms - +0.01ms)
    preact-local vs preact-main

Results

create10k

duration

VersionAvg timevs preact-localvs preact-main
preact-local839.33ms - 843.85ms-unsure 🔍
-0% - +1%
-1.19ms - +5.88ms
preact-main836.53ms - 841.95msunsure 🔍
-1% - +0%
-5.88ms - +1.19ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local19.21ms - 19.25ms-unsure 🔍
-0% - +0%
-0.04ms - +0.02ms
preact-main19.22ms - 19.26msunsure 🔍
-0% - +0%
-0.02ms - +0.04ms
-
filter-list

duration

VersionAvg timevs preact-localvs preact-main
preact-local16.52ms - 16.70ms-unsure 🔍
-0% - +1%
-0.02ms - +0.17ms
preact-main16.52ms - 16.55msunsure 🔍
-1% - +0%
-0.17ms - +0.02ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local1.56ms - 1.57ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main1.56ms - 1.57msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
hydrate1k

duration

VersionAvg timevs preact-localvs preact-main
preact-local41.31ms - 42.56ms-unsure 🔍
-1% - +3%
-0.25ms - +1.26ms
preact-main41.02ms - 41.84msunsure 🔍
-3% - +1%
-1.26ms - +0.25ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local4.99ms - 5.19ms-unsure 🔍
-2% - +3%
-0.09ms - +0.15ms
preact-main4.98ms - 5.13msunsure 🔍
-3% - +2%
-0.15ms - +0.09ms
-
many-updates

duration

VersionAvg timevs preact-localvs preact-main
preact-local16.04ms - 16.61ms-unsure 🔍
-2% - +2%
-0.28ms - +0.38ms
preact-main16.11ms - 16.44msunsure 🔍
-2% - +2%
-0.38ms - +0.28ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local3.75ms - 3.76ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main3.75ms - 3.76msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
replace1k
  • Browser: chrome-headless
  • Sample size: 100
  • Built by: CI #5824
  • Commit: 90789f0

duration

VersionAvg timevs preact-localvs preact-main
preact-local55.67ms - 57.03ms-unsure 🔍
-1% - +2%
-0.55ms - +1.27ms
preact-main55.39ms - 56.58msunsure 🔍
-2% - +1%
-1.27ms - +0.55ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local3.03ms - 3.03ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main3.03ms - 3.03msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-

run-warmup-0

VersionAvg timevs preact-localvs preact-main
preact-local26.96ms - 27.71ms-unsure 🔍
-3% - +1%
-0.91ms - +0.19ms
preact-main27.29ms - 28.11msunsure 🔍
-1% - +3%
-0.19ms - +0.91ms
-

run-warmup-1

VersionAvg timevs preact-localvs preact-main
preact-local32.52ms - 33.79ms-unsure 🔍
-3% - +3%
-0.96ms - +0.86ms
preact-main32.56ms - 33.86msunsure 🔍
-3% - +3%
-0.86ms - +0.96ms
-

run-warmup-2

VersionAvg timevs preact-localvs preact-main
preact-local31.98ms - 33.61ms-unsure 🔍
-5% - +2%
-1.51ms - +0.83ms
preact-main32.30ms - 33.97msunsure 🔍
-3% - +5%
-0.83ms - +1.51ms
-

run-warmup-3

VersionAvg timevs preact-localvs preact-main
preact-local25.96ms - 26.30ms-unsure 🔍
-1% - +0%
-0.37ms - +0.11ms
preact-main26.09ms - 26.43msunsure 🔍
-0% - +1%
-0.11ms - +0.37ms
-

run-warmup-4

VersionAvg timevs preact-localvs preact-main
preact-local27.04ms - 28.20ms-unsure 🔍
-5% - +1%
-1.31ms - +0.22ms
preact-main27.66ms - 28.67msunsure 🔍
-1% - +5%
-0.22ms - +1.31ms
-

run-final

VersionAvg timevs preact-localvs preact-main
preact-local21.18ms - 21.56ms-unsure 🔍
-1% - +2%
-0.19ms - +0.35ms
preact-main21.10ms - 21.47msunsure 🔍
-2% - +1%
-0.35ms - +0.19ms
-
text-update
  • Browser: chrome-headless
  • Sample size: 200
  • Built by: CI #5824
  • Commit: 90789f0

duration

VersionAvg timevs preact-localvs preact-main
preact-local1.93ms - 2.04ms-unsure 🔍
-4% - +4%
-0.08ms - +0.07ms
preact-main1.93ms - 2.04msunsure 🔍
-4% - +4%
-0.07ms - +0.08ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local1.05ms - 1.10ms-unsure 🔍
-2% - +5%
-0.02ms - +0.05ms
preact-main1.04ms - 1.09msunsure 🔍
-5% - +2%
-0.05ms - +0.02ms
-
todo

duration

VersionAvg timevs preact-localvs preact-main
preact-local28.49ms - 29.04ms-unsure 🔍
-2% - +1%
-0.52ms - +0.23ms
preact-main28.67ms - 29.16msunsure 🔍
-1% - +2%
-0.23ms - +0.52ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local1.28ms - 1.28ms-unsure 🔍
-0% - +0%
-0.00ms - +0.00ms
preact-main1.28ms - 1.28msunsure 🔍
-0% - +0%
-0.00ms - +0.00ms
-
update10th1k

duration

VersionAvg timevs preact-localvs preact-main
preact-local42.07ms - 44.55ms-unsure 🔍
-5% - +3%
-2.04ms - +1.34ms
preact-main42.51ms - 44.81msunsure 🔍
-3% - +5%
-1.34ms - +2.04ms
-

usedJSHeapSize

VersionAvg timevs preact-localvs preact-main
preact-local2.97ms - 2.98ms-unsure 🔍
-0% - +0%
-0.01ms - +0.01ms
preact-main2.97ms - 2.98msunsure 🔍
-0% - +0%
-0.01ms - +0.01ms
-

tachometer-reporter-action v2 for CI

@github-actions

Copy link
Copy Markdown

Size Change: +8 B (+0.05%)

Total Size: 15.8 kB

📦 View Changed
Filename Size Change
hooks/dist/hooks.mjs 1.57 kB +8 B (+0.51%)
ℹ️ View Unchanged
Filename Size
compat/dist/compat.mjs 3.89 kB
debug/dist/debug.mjs 3.88 kB
devtools/dist/devtools.mjs 274 B
dist/preact.mjs 4.88 kB
jsx-runtime/dist/jsxRuntime.mjs 856 B
test-utils/dist/testUtils.mjs 473 B

compressed-size-action

@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 99.298% (+0.001%) from 99.297% — perf/cold-unmount-queue into main

@JoviDeCroock
JoviDeCroock deleted the perf/cold-unmount-queue branch August 10, 2026 05:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants