Skip to content

Add onTestFinished cleanup hook to test framework#223

Merged
frostney merged 2 commits into
mainfrom
t3code/test-lifecycle-coverage
Apr 8, 2026
Merged

Add onTestFinished cleanup hook to test framework#223
frostney merged 2 commits into
mainfrom
t3code/test-lifecycle-coverage

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 8, 2026

Summary

  • Added a new onTestFinished(fn) lifecycle hook for per-test cleanup in the JS test framework.
  • Ensured cleanup callbacks run after afterEach hooks and are reset between tests.
  • Added end-to-end coverage for callback ordering, scoping, async cleanup, and nested suite behavior.
  • Updated testing docs and AGENTS guidance to describe the new hook.

Testing

  • Not run
  • Existing coverage added in tests/language/testing/onTestFinished.js
  • Framework implementation updated in units/Goccia.Builtins.TestAssertions.pas
  • Documentation updated in docs/testing.md and AGENTS.md

- Register per-test cleanup callbacks for the test framework
- Document lifecycle hook order and add coverage for scoping and async callbacks
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 39d50d4c-3901-4732-afcf-a6b77febe4bb

📥 Commits

Reviewing files that changed from the base of the PR and between f5c8ab3 and c43c914.

📒 Files selected for processing (2)
  • tests/language/testing/onTestFinished.js
  • units/Goccia.Builtins.TestAssertions.pas

📝 Walkthrough

Walkthrough

Adds a new per-test cleanup hook onTestFinished(fn) that runs callbacks registered during a test after all afterEach hooks complete, scoped to the current test. Documentation, Delphi backend support, and tests for ordering, scoping, and async behavior are included.

Changes

Cohort / File(s) Summary
Documentation
AGENTS.md, docs/testing.md
Documented async-capable lifecycle hooks (beforeAll, beforeEach, afterEach, afterAll) and added onTestFinished(fn) description, execution timing (after afterEach), registration semantics, ordering/isolation guarantees, reference table, and an inline example.
Implementation (Delphi backend)
units/Goccia.Builtins.TestAssertions.pas
Added FOnTestFinishedCallbacks collection and OnTestFinished method exposed as native function (arity 1); register callbacks from test bodies; clear per-test callbacks before beforeEach; execute callbacks after afterEach (in a finally block) so they run regardless of test outcome.
Tests
tests/language/testing/onTestFinished.js
New test suite covering: callback execution order, scoping (no leakage across tests), async callback support, interaction with nested afterEach hooks, and that callbacks run after afterEach.

Sequence Diagram(s)

sequenceDiagram
  participant TR as Test Runner
  participant BE as beforeEach hooks
  participant TB as Test Body
  participant AE as afterEach hooks
  participant OF as onTestFinished callbacks

  TR->>BE: run beforeEach
  BE-->>TR: complete
  TR->>TB: execute test body\n(register onTestFinished)
  TB-->>TR: complete
  TR->>AE: run afterEach hooks (may be nested)
  AE-->>TR: complete
  TR->>OF: invoke registered callbacks\n(in registration order)
  OF-->>TR: complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete; it does not check the required testing checkboxes and instead provides a custom format ('Not run', 'Existing coverage added') that deviates from the template. Replace the custom Testing section with the template's checklist format, explicitly checking or unchecking each required item (regressions, documentation, Pascal tests, benchmarks) with clear justification.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding a new onTestFinished cleanup hook to the test framework, which is the primary objective of the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/language/testing/onTestFinished.js`:
- Around line 54-77: The tests register onTestFinished callbacks but never
assert they ran; declare the arrays (asyncLog, marker) in the outer describe
scope (not as locals inside each test), push values from the onTestFinished
callbacks in the respective tests (use asyncLog and marker as currently named),
then change the final "cleanup ran for previous test" test to assert that
asyncLog contains "async-cleanup" and marker contains "cleanup" (or await/poll
briefly if callbacks run asynchronously) so the suite verifies the cleanup
callbacks actually executed.

In `@units/Goccia.Builtins.TestAssertions.pas`:
- Line 2348: The literal hook name 'onTestFinished' is duplicated; create a
shared constant PROP_ON_TEST_FINISHED in Goccia.Constants.PropertyNames and
replace all hardcoded occurrences with that constant (for example update the
AScope.DefineLexicalBinding call that currently uses
TGocciaNativeFunctionValue.Create(OnTestFinished, 'onTestFinished', 1) to use
PROP_ON_TEST_FINISHED instead) and update the corresponding
validation/registration sites (the other occurrences referenced around the
AScope.DefineLexicalBinding usage and the blocks near the other mentions) so
both registration and validation use
Goccia.Constants.PropertyNames.PROP_ON_TEST_FINISHED consistently.
- Line 2322: FOnTestFinishedCallbacks is storing JS callback values in a
Pascal-only collection (TGocciaArgumentsCollection) without GC roots; wrap
stored callbacks with the runtime's temporary rooting APIs: call AddTempRoot
when a callback is added to FOnTestFinishedCallbacks and call RemoveTempRoot
when the callback is removed or when the collection is cleared/finalized (also
ensure the destructor of the owner removes roots for any remaining elements);
update the code paths that insert/remove callbacks (references:
FOnTestFinishedCallbacks, TGocciaArgumentsCollection) and mirror this pattern
for the other occurrences noted (around lines handling the collections at 2370,
2835, 2909–2910, 3350–3359) so values held only by Pascal are protected for the
duration they are needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1d14d673-a64a-4ec7-816c-b99970af8528

📥 Commits

Reviewing files that changed from the base of the PR and between be84303 and f5c8ab3.

📒 Files selected for processing (4)
  • AGENTS.md
  • docs/testing.md
  • tests/language/testing/onTestFinished.js
  • units/Goccia.Builtins.TestAssertions.pas

Comment thread tests/language/testing/onTestFinished.js
Comment thread units/Goccia.Builtins.TestAssertions.pas
Comment thread units/Goccia.Builtins.TestAssertions.pas
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3846 3846
Tests Passed 3805 ✅ 3846 ✅
Tests Skipped 41 0
Tests Test Duration 267.7ms 261.1ms
Tests Lex 73.3ms 48.6ms
Tests Parse 95.1ms 95.9ms
Tests Compile 58.6ms
Tests Execute 282.7ms 289.3ms
Tests Engine Total 451.0ms 492.4ms
Benchmarks Total 274 274
Benchmarks Duration 7.53min 6.57min

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

Benchmark Results

274 benchmarks

Interpreted: 🟢 183 improved · 🔴 17 regressed · 74 unchanged · avg +3.3%
Bytecode: 🟢 151 improved · 🔴 57 regressed · 66 unchanged · avg +1.9%

arraybuffer.js — Interp: 🟢 13, 🔴 1 · avg +4.7% · Bytecode: 🟢 11, 🔴 1, 2 unch. · avg +5.0%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 452,163 ops/sec [449,870..453,670] → 487,051 ops/sec [484,229..493,852] 🟢 +7.7% 494,186 ops/sec [492,599..497,435] → 543,088 ops/sec [536,441..549,895] 🟢 +9.9%
create ArrayBuffer(64) 431,926 ops/sec [431,358..432,910] → 469,783 ops/sec [467,539..471,369] 🟢 +8.8% 470,425 ops/sec [469,444..472,399] → 513,809 ops/sec [503,535..518,173] 🟢 +9.2%
create ArrayBuffer(1024) 339,593 ops/sec [338,734..339,646] → 341,906 ops/sec [341,399..348,249] 🟢 +0.7% 362,216 ops/sec [360,659..362,382] → 367,871 ops/sec [366,048..370,979] 🟢 +1.6%
create ArrayBuffer(8192) 153,632 ops/sec [152,484..154,425] → 137,640 ops/sec [130,168..141,344] 🔴 -10.4% 160,793 ops/sec [159,831..161,318] → 143,227 ops/sec [133,051..145,043] 🔴 -10.9%
slice full buffer (64 bytes) 509,138 ops/sec [505,729..510,495] → 527,291 ops/sec [520,135..530,411] 🟢 +3.6% 592,674 ops/sec [586,772..595,028] → 628,115 ops/sec [625,445..629,910] 🟢 +6.0%
slice half buffer (512 of 1024 bytes) 435,903 ops/sec [434,842..436,257] → 453,089 ops/sec [449,983..454,801] 🟢 +3.9% 507,819 ops/sec [506,025..508,064] → 536,484 ops/sec [535,980..537,490] 🟢 +5.6%
slice with negative indices 420,583 ops/sec [419,065..423,433] → 450,302 ops/sec [448,980..452,113] 🟢 +7.1% 548,204 ops/sec [547,586..550,159] → 580,628 ops/sec [578,708..582,581] 🟢 +5.9%
slice empty range 482,243 ops/sec [478,373..484,008] → 506,616 ops/sec [501,468..508,374] 🟢 +5.1% 588,718 ops/sec [586,789..591,008] → 621,628 ops/sec [619,462..624,892] 🟢 +5.6%
byteLength access 1,275,293 ops/sec [1,270,447..1,276,327] → 1,370,334 ops/sec [1,367,680..1,372,353] 🟢 +7.5% 1,512,271 ops/sec [1,507,299..1,515,885] → 1,612,927 ops/sec [1,602,280..1,621,559] 🟢 +6.7%
Symbol.toStringTag access 966,977 ops/sec [964,256..968,939] → 1,051,884 ops/sec [1,046,955..1,053,366] 🟢 +8.8% 1,007,740 ops/sec [1,003,832..1,010,506] → 1,133,778 ops/sec [974,452..1,141,104] ~ overlap (+12.5%)
ArrayBuffer.isView 723,864 ops/sec [722,102..728,226] → 798,786 ops/sec [792,048..804,006] 🟢 +10.4% 813,601 ops/sec [804,099..816,893] → 885,092 ops/sec [861,220..888,894] 🟢 +8.8%
clone ArrayBuffer(64) 409,165 ops/sec [407,900..409,724] → 430,014 ops/sec [428,398..431,458] 🟢 +5.1% 476,842 ops/sec [474,918..479,795] → 507,771 ops/sec [507,186..508,846] 🟢 +6.5%
clone ArrayBuffer(1024) 317,576 ops/sec [314,890..318,573] → 321,671 ops/sec [318,749..323,291] 🟢 +1.3% 363,585 ops/sec [359,536..365,253] → 355,707 ops/sec [354,566..361,571] ~ overlap (-2.2%)
clone ArrayBuffer inside object 259,882 ops/sec [255,571..260,191] → 277,344 ops/sec [276,504..279,812] 🟢 +6.7% 297,345 ops/sec [294,814..300,235] → 310,840 ops/sec [307,462..311,373] 🟢 +4.5%
arrays.js — Interp: 🟢 18, 1 unch. · avg +7.6% · Bytecode: 🟢 16, 🔴 2, 1 unch. · avg +4.0%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 12,875 ops/sec [12,819..12,923] → 14,141 ops/sec [14,034..14,172] 🟢 +9.8% 14,484 ops/sec [14,118..14,678] → 15,436 ops/sec [15,367..15,521] 🟢 +6.6%
Array.from 10 elements 222,617 ops/sec [222,082..224,064] → 230,017 ops/sec [228,753..230,782] 🟢 +3.3% 237,081 ops/sec [235,571..238,194] → 247,317 ops/sec [245,698..247,814] 🟢 +4.3%
Array.of 10 elements 272,954 ops/sec [272,095..273,841] → 289,219 ops/sec [288,036..290,283] 🟢 +6.0% 298,805 ops/sec [298,041..299,435] → 315,881 ops/sec [313,068..320,404] 🟢 +5.7%
spread into new array 328,402 ops/sec [327,594..329,435] → 339,354 ops/sec [337,966..341,842] 🟢 +3.3% 193,318 ops/sec [192,443..194,958] → 200,989 ops/sec [197,486..201,887] 🟢 +4.0%
map over 50 elements 23,953 ops/sec [23,836..24,128] → 25,910 ops/sec [25,684..25,939] 🟢 +8.2% 25,932 ops/sec [25,903..26,006] → 27,453 ops/sec [27,107..27,539] 🟢 +5.9%
filter over 50 elements 21,853 ops/sec [21,168..21,889] → 23,983 ops/sec [23,844..24,104] 🟢 +9.7% 23,574 ops/sec [23,509..23,620] → 22,691 ops/sec [22,564..22,744] 🔴 -3.7%
reduce sum 50 elements 24,610 ops/sec [24,563..24,688] → 27,239 ops/sec [26,914..27,274] 🟢 +10.7% 19,004 ops/sec [18,947..19,006] → 19,761 ops/sec [19,635..19,783] 🟢 +4.0%
forEach over 50 elements 21,966 ops/sec [21,896..22,017] → 24,098 ops/sec [23,995..24,184] 🟢 +9.7% 27,574 ops/sec [27,490..27,666] → 28,561 ops/sec [28,324..28,657] 🟢 +3.6%
find in 50 elements 31,076 ops/sec [30,985..31,196] → 34,214 ops/sec [33,807..34,573] 🟢 +10.1% 30,391 ops/sec [30,306..30,426] → 32,342 ops/sec [32,272..32,537] 🟢 +6.4%
sort 20 elements 11,826 ops/sec [11,796..11,876] → 12,960 ops/sec [12,920..13,025] 🟢 +9.6% 13,367 ops/sec [13,288..13,392] → 13,994 ops/sec [13,918..14,045] 🟢 +4.7%
flat nested array 111,281 ops/sec [111,056..111,523] → 116,169 ops/sec [115,962..116,637] 🟢 +4.4% 128,786 ops/sec [128,609..129,268] → 133,711 ops/sec [132,426..134,024] 🟢 +3.8%
flatMap 70,651 ops/sec [70,321..70,833] → 75,383 ops/sec [75,170..75,467] 🟢 +6.7% 80,920 ops/sec [80,302..81,838] → 85,445 ops/sec [84,625..85,679] 🟢 +5.6%
map inside map (5x5) 19,722 ops/sec [19,616..19,811] → 21,281 ops/sec [21,215..21,347] 🟢 +7.9% 22,388 ops/sec [22,320..22,435] → 23,640 ops/sec [23,423..23,780] 🟢 +5.6%
filter inside map (5x10) 15,097 ops/sec [15,035..15,146] → 16,513 ops/sec [16,366..16,542] 🟢 +9.4% 16,660 ops/sec [16,448..16,818] → 16,351 ops/sec [16,248..16,434] 🔴 -1.9%
reduce inside map (5x10) 18,156 ops/sec [18,082..18,228] → 20,009 ops/sec [19,833..20,103] 🟢 +10.2% 15,917 ops/sec [15,855..15,961] → 16,652 ops/sec [16,069..16,797] 🟢 +4.6%
forEach inside forEach (5x10) 16,016 ops/sec [15,908..16,099] → 17,455 ops/sec [17,134..17,532] 🟢 +9.0% 16,672 ops/sec [16,602..16,711] → 17,871 ops/sec [17,763..17,958] 🟢 +7.2%
find inside some (10x10) 12,856 ops/sec [12,822..12,887] → 13,933 ops/sec [13,800..14,112] 🟢 +8.4% 12,944 ops/sec [12,880..12,963] → 13,760 ops/sec [13,709..13,853] 🟢 +6.3%
map+filter chain nested (5x20) 4,996 ops/sec [4,984..5,008] → 5,390 ops/sec [5,363..5,396] 🟢 +7.9% 5,462 ops/sec [5,425..5,483] → 5,545 ops/sec [5,487..5,587] 🟢 +1.5%
reduce flatten (10x5) 38,187 ops/sec [37,949..38,412] → 38,250 ops/sec [37,902..38,792] ~ overlap (+0.2%) 17,482 ops/sec [17,427..17,604] → 17,718 ops/sec [16,980..17,934] ~ overlap (+1.3%)
async-await.js — Interp: 🟢 6 · avg +6.4% · Bytecode: 🟢 6 · avg +5.0%
Benchmark Interpreted Δ Bytecode Δ
single await 366,793 ops/sec [366,673..367,034] → 392,773 ops/sec [386,791..395,519] 🟢 +7.1% 392,930 ops/sec [392,223..394,799] → 414,773 ops/sec [413,260..417,843] 🟢 +5.6%
multiple awaits 166,799 ops/sec [165,933..167,043] → 181,178 ops/sec [179,822..181,435] 🟢 +8.6% 173,622 ops/sec [172,941..173,929] → 181,826 ops/sec [180,537..182,980] 🟢 +4.7%
await non-Promise value 828,099 ops/sec [817,287..832,007] → 865,084 ops/sec [861,678..875,044] 🟢 +4.5% 1,088,134 ops/sec [1,083,556..1,090,925] → 1,169,789 ops/sec [1,167,112..1,179,031] 🟢 +7.5%
await with try/catch 358,065 ops/sec [355,585..359,356] → 383,360 ops/sec [382,252..385,953] 🟢 +7.1% 390,398 ops/sec [387,042..391,769] → 407,905 ops/sec [400,001..416,147] 🟢 +4.5%
await Promise.all 49,916 ops/sec [49,358..50,029] → 53,318 ops/sec [53,208..53,873] 🟢 +6.8% 50,925 ops/sec [49,407..51,094] → 53,299 ops/sec [53,135..54,243] 🟢 +4.7%
nested async function call 191,647 ops/sec [191,006..192,008] → 200,143 ops/sec [198,059..201,016] 🟢 +4.4% 223,220 ops/sec [221,696..223,863] → 230,351 ops/sec [229,623..231,267] 🟢 +3.2%
classes.js — Interp: 🟢 22, 🔴 1, 8 unch. · avg +3.4% · Bytecode: 🟢 4, 🔴 11, 16 unch. · avg -2.3%
Benchmark Interpreted Δ Bytecode Δ
simple class new 139,031 ops/sec [138,896..140,363] → 144,916 ops/sec [144,752..145,041] 🟢 +4.2% 203,723 ops/sec [203,533..204,743] → 206,326 ops/sec [203,599..208,031] ~ overlap (+1.3%)
class with defaults 110,509 ops/sec [109,879..110,865] → 114,780 ops/sec [114,193..115,725] 🟢 +3.9% 144,803 ops/sec [143,759..145,214] → 146,480 ops/sec [144,991..147,921] ~ overlap (+1.2%)
50 instances via Array.from 5,611 ops/sec [5,572..5,645] → 5,973 ops/sec [5,953..5,982] 🟢 +6.4% 7,917 ops/sec [7,848..8,019] → 8,320 ops/sec [8,314..8,327] 🟢 +5.1%
instance method call 71,108 ops/sec [70,617..71,436] → 75,977 ops/sec [75,696..76,182] 🟢 +6.8% 91,216 ops/sec [90,710..91,386] → 92,981 ops/sec [91,988..93,589] 🟢 +1.9%
static method call 113,737 ops/sec [112,906..114,030] → 120,514 ops/sec [120,181..120,883] 🟢 +6.0% 180,033 ops/sec [179,754..181,064] → 182,131 ops/sec [180,238..184,017] ~ overlap (+1.2%)
single-level inheritance 55,996 ops/sec [55,456..56,158] → 58,941 ops/sec [58,585..59,107] 🟢 +5.3% 73,341 ops/sec [72,822..73,947] → 75,134 ops/sec [73,570..75,183] ~ overlap (+2.4%)
two-level inheritance 47,823 ops/sec [47,729..47,935] → 50,837 ops/sec [50,636..51,097] 🟢 +6.3% 61,191 ops/sec [59,981..62,063] → 62,473 ops/sec [60,319..64,022] ~ overlap (+2.1%)
private field access 70,535 ops/sec [70,429..70,941] → 78,200 ops/sec [77,761..78,792] 🟢 +10.9% 88,788 ops/sec [88,151..89,496] → 92,720 ops/sec [92,383..93,161] 🟢 +4.4%
private methods 78,816 ops/sec [78,310..79,133] → 84,369 ops/sec [83,928..84,652] 🟢 +7.0% 98,050 ops/sec [96,717..99,499] → 98,814 ops/sec [98,023..99,492] ~ overlap (+0.8%)
getter/setter access 75,782 ops/sec [74,940..75,910] → 79,563 ops/sec [79,421..80,207] 🟢 +5.0% 105,086 ops/sec [104,799..105,325] → 107,744 ops/sec [107,182..107,985] 🟢 +2.5%
class decorator (identity) 92,341 ops/sec [91,455..94,167] → 97,147 ops/sec [95,650..98,107] 🟢 +5.2% 103,243 ops/sec [102,752..104,768] → 101,369 ops/sec [100,392..102,694] 🔴 -1.8%
class decorator (wrapping) 55,037 ops/sec [54,939..55,205] → 56,450 ops/sec [55,793..57,105] 🟢 +2.6% 58,911 ops/sec [56,874..61,846] → 59,869 ops/sec [56,726..63,274] ~ overlap (+1.6%)
identity method decorator 65,665 ops/sec [64,781..66,664] → 68,318 ops/sec [67,901..69,182] 🟢 +4.0% 87,452 ops/sec [82,296..93,266] → 85,135 ops/sec [79,495..90,048] ~ overlap (-2.6%)
wrapping method decorator 51,953 ops/sec [51,571..52,232] → 54,607 ops/sec [54,323..54,700] 🟢 +5.1% 63,160 ops/sec [60,372..68,870] → 65,909 ops/sec [58,819..70,377] ~ overlap (+4.4%)
stacked method decorators (x3) 35,497 ops/sec [35,371..35,550] → 36,173 ops/sec [35,887..36,771] 🟢 +1.9% 42,747 ops/sec [40,948..46,594] → 42,384 ops/sec [39,638..44,924] ~ overlap (-0.8%)
identity field decorator 71,390 ops/sec [70,994..72,393] → 73,797 ops/sec [72,798..74,298] 🟢 +3.4% 76,025 ops/sec [74,100..80,964] → 75,839 ops/sec [70,127..80,768] ~ overlap (-0.2%)
field initializer decorator 59,577 ops/sec [59,400..59,596] → 61,688 ops/sec [60,487..62,374] 🟢 +3.5% 65,230 ops/sec [60,407..69,748] → 61,238 ops/sec [59,667..63,396] ~ overlap (-6.1%)
getter decorator (identity) 64,645 ops/sec [64,572..64,831] → 67,578 ops/sec [67,127..68,100] 🟢 +4.5% 74,794 ops/sec [73,898..78,249] → 71,218 ops/sec [69,585..72,963] 🔴 -4.8%
setter decorator (identity) 54,678 ops/sec [54,521..54,961] → 57,499 ops/sec [56,561..57,903] 🟢 +5.2% 61,088 ops/sec [60,531..62,123] → 58,633 ops/sec [58,015..59,714] 🔴 -4.0%
static method decorator 71,288 ops/sec [70,915..71,536] → 73,336 ops/sec [72,819..73,853] 🟢 +2.9% 81,460 ops/sec [79,532..84,445] → 76,574 ops/sec [73,917..78,034] 🔴 -6.0%
static field decorator 82,592 ops/sec [81,854..83,203] → 83,124 ops/sec [81,809..84,393] ~ overlap (+0.6%) 88,235 ops/sec [83,431..94,682] → 80,714 ops/sec [78,567..87,638] ~ overlap (-8.5%)
private method decorator 53,187 ops/sec [53,003..53,510] → 55,113 ops/sec [54,117..55,413] 🟢 +3.6% 70,976 ops/sec [67,775..74,348] → 67,062 ops/sec [63,746..69,891] ~ overlap (-5.5%)
private field decorator 59,158 ops/sec [58,748..59,523] → 60,974 ops/sec [60,427..61,267] 🟢 +3.1% 68,114 ops/sec [64,735..72,810] → 59,297 ops/sec [57,636..60,950] 🔴 -12.9%
plain auto-accessor (no decorator) 103,234 ops/sec [101,187..104,555] → 103,894 ops/sec [103,130..108,090] ~ overlap (+0.6%) 96,604 ops/sec [94,423..101,422] → 102,663 ops/sec [96,756..114,281] ~ overlap (+6.3%)
auto-accessor with decorator 54,745 ops/sec [53,711..56,133] → 54,138 ops/sec [53,202..55,999] ~ overlap (-1.1%) 61,237 ops/sec [58,400..67,596] → 51,988 ops/sec [49,377..56,906] 🔴 -15.1%
decorator writing metadata 43,994 ops/sec [43,964..44,121] → 44,118 ops/sec [43,427..44,774] ~ overlap (+0.3%) 48,001 ops/sec [46,929..54,651] → 48,059 ops/sec [47,293..53,148] ~ overlap (+0.1%)
static getter read 125,989 ops/sec [125,619..126,795] → 123,849 ops/sec [123,716..125,027] 🔴 -1.7% 175,086 ops/sec [173,027..177,118] → 157,026 ops/sec [156,092..159,506] 🔴 -10.3%
static getter/setter pair 97,406 ops/sec [96,838..97,907] → 98,039 ops/sec [97,043..98,836] ~ overlap (+0.6%) 119,118 ops/sec [116,905..121,001] → 113,193 ops/sec [110,265..115,959] 🔴 -5.0%
inherited static getter 75,939 ops/sec [75,677..76,207] → 76,564 ops/sec [75,711..77,084] ~ overlap (+0.8%) 100,162 ops/sec [99,828..102,696] → 88,128 ops/sec [87,672..88,398] 🔴 -12.0%
inherited static setter 82,546 ops/sec [82,116..82,642] → 82,044 ops/sec [71,798..82,659] ~ overlap (-0.6%) 102,605 ops/sec [102,338..106,048] → 96,459 ops/sec [95,095..100,679] 🔴 -6.0%
inherited static getter with this binding 70,835 ops/sec [70,612..71,092] → 70,520 ops/sec [70,189..71,078] ~ overlap (-0.4%) 91,380 ops/sec [90,096..92,520] → 85,772 ops/sec [85,050..87,605] 🔴 -6.1%
closures.js — Interp: 🟢 10, 1 unch. · avg +3.5% · Bytecode: 🟢 8, 🔴 1, 2 unch. · avg +2.1%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 132,735 ops/sec [132,273..133,632] → 137,243 ops/sec [136,443..138,260] 🟢 +3.4% 277,798 ops/sec [274,224..284,153] → 274,055 ops/sec [268,874..277,032] ~ overlap (-1.3%)
closure over multiple variables 117,065 ops/sec [116,612..117,772] → 120,457 ops/sec [119,777..121,571] 🟢 +2.9% 192,322 ops/sec [190,570..194,757] → 197,901 ops/sec [196,231..203,084] 🟢 +2.9%
nested closures 124,191 ops/sec [123,671..124,894] → 127,150 ops/sec [121,648..127,781] ~ overlap (+2.4%) 221,639 ops/sec [218,075..235,561] → 224,548 ops/sec [220,457..240,611] ~ overlap (+1.3%)
function as argument 91,266 ops/sec [90,713..91,531] → 94,800 ops/sec [93,839..95,596] 🟢 +3.9% 248,887 ops/sec [248,494..249,751] → 255,968 ops/sec [253,130..257,454] 🟢 +2.8%
function returning function 116,395 ops/sec [115,251..116,978] → 119,733 ops/sec [118,478..120,343] 🟢 +2.9% 278,616 ops/sec [277,164..280,200] → 285,261 ops/sec [282,009..287,155] 🟢 +2.4%
compose two functions 69,625 ops/sec [69,389..69,925] → 71,579 ops/sec [71,218..71,946] 🟢 +2.8% 146,760 ops/sec [146,379..148,373] → 153,562 ops/sec [152,698..155,313] 🟢 +4.6%
fn.call 148,803 ops/sec [147,168..149,628] → 151,398 ops/sec [150,823..151,718] 🟢 +1.7% 219,199 ops/sec [214,909..221,790] → 229,753 ops/sec [226,788..231,916] 🟢 +4.8%
fn.apply 108,733 ops/sec [108,521..108,919] → 110,556 ops/sec [110,210..110,579] 🟢 +1.7% 157,103 ops/sec [155,133..158,023] → 148,561 ops/sec [146,201..148,670] 🔴 -5.4%
fn.bind 139,129 ops/sec [138,030..139,529] → 145,443 ops/sec [144,994..145,827] 🟢 +4.5% 279,296 ops/sec [276,957..281,582] → 282,363 ops/sec [281,718..282,655] 🟢 +1.1%
recursive sum to 50 11,653 ops/sec [11,629..11,664] → 12,361 ops/sec [12,283..12,436] 🟢 +6.1% 23,317 ops/sec [23,180..23,370] → 24,279 ops/sec [24,192..24,374] 🟢 +4.1%
recursive tree traversal 19,875 ops/sec [19,865..19,913] → 21,185 ops/sec [21,076..21,296] 🟢 +6.6% 34,213 ops/sec [33,849..34,370] → 36,352 ops/sec [35,970..36,593] 🟢 +6.3%
collections.js — Interp: 🟢 6, 🔴 2, 4 unch. · avg +1.4% · Bytecode: 🟢 5, 🔴 4, 3 unch. · avg +1.2%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 6,699 ops/sec [6,668..6,724] → 7,040 ops/sec [7,030..7,088] 🟢 +5.1% 7,036 ops/sec [7,019..7,062] → 7,146 ops/sec [7,061..7,172] ~ overlap (+1.6%)
has lookup (50 elements) 86,521 ops/sec [86,173..86,990] → 90,177 ops/sec [89,876..90,639] 🟢 +4.2% 95,223 ops/sec [94,852..95,376] → 96,932 ops/sec [96,502..97,821] 🟢 +1.8%
delete elements 46,299 ops/sec [46,088..46,541] → 48,035 ops/sec [47,848..48,190] 🟢 +3.7% 48,342 ops/sec [48,162..48,444] → 49,658 ops/sec [49,491..49,727] 🟢 +2.7%
forEach iteration 15,136 ops/sec [15,025..15,185] → 16,367 ops/sec [16,194..16,526] 🟢 +8.1% 14,522 ops/sec [14,347..14,853] → 16,455 ops/sec [16,396..16,537] 🟢 +13.3%
spread to array 29,114 ops/sec [29,035..29,294] → 27,164 ops/sec [27,008..27,344] 🔴 -6.7% 217,142 ops/sec [215,217..218,142] → 202,827 ops/sec [202,522..203,030] 🔴 -6.6%
deduplicate array 37,456 ops/sec [37,255..37,688] → 37,155 ops/sec [36,849..37,461] ~ overlap (-0.8%) 70,115 ops/sec [69,270..70,498] → 72,816 ops/sec [72,458..73,554] 🟢 +3.9%
set 50 entries 5,050 ops/sec [5,010..5,062] → 5,061 ops/sec [5,026..5,096] ~ overlap (+0.2%) 5,587 ops/sec [5,502..5,602] → 5,441 ops/sec [5,322..5,545] ~ overlap (-2.6%)
get lookup (50 entries) 85,014 ops/sec [84,580..85,149] → 84,300 ops/sec [84,057..84,708] ~ overlap (-0.8%) 88,863 ops/sec [88,388..89,077] → 88,914 ops/sec [88,474..89,405] ~ overlap (+0.1%)
has check 126,070 ops/sec [125,248..126,532] → 127,839 ops/sec [127,491..128,969] 🟢 +1.4% 136,784 ops/sec [136,157..136,918] → 135,608 ops/sec [134,611..136,040] 🔴 -0.9%
delete entries 44,872 ops/sec [44,756..44,967] → 45,003 ops/sec [44,560..45,147] ~ overlap (+0.3%) 45,976 ops/sec [45,714..46,161] → 45,594 ops/sec [45,145..45,675] 🔴 -0.8%
forEach iteration 15,254 ops/sec [15,061..15,450] → 16,583 ops/sec [16,457..16,701] 🟢 +8.7% 15,135 ops/sec [14,986..15,222] → 16,503 ops/sec [16,419..16,828] 🟢 +9.0%
keys/values/entries 7,953 ops/sec [7,948..7,985] → 7,385 ops/sec [7,333..7,426] 🔴 -7.1% 27,779 ops/sec [27,602..28,434] → 25,748 ops/sec [25,264..26,061] 🔴 -7.3%
destructuring.js — Interp: 🟢 10, 🔴 2, 10 unch. · avg +2.1% · Bytecode: 🟢 5, 🔴 14, 3 unch. · avg -1.9%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 369,774 ops/sec [362,940..372,770] → 373,342 ops/sec [370,687..374,050] ~ overlap (+1.0%) 279,224 ops/sec [277,288..279,724] → 252,885 ops/sec [250,335..253,709] 🔴 -9.4%
with rest element 239,720 ops/sec [237,900..241,073] → 237,742 ops/sec [236,611..240,263] ~ overlap (-0.8%) 209,069 ops/sec [207,387..213,688] → 201,089 ops/sec [197,303..203,113] 🔴 -3.8%
with defaults 378,934 ops/sec [375,506..379,573] → 371,074 ops/sec [369,170..376,224] ~ overlap (-2.1%) 312,440 ops/sec [310,828..318,136] → 295,006 ops/sec [288,782..298,339] 🔴 -5.6%
skip elements 386,255 ops/sec [385,323..388,491] → 397,578 ops/sec [392,703..402,898] 🟢 +2.9% 285,131 ops/sec [284,494..295,141] → 277,710 ops/sec [274,570..278,714] 🔴 -2.6%
nested array destructuring 163,129 ops/sec [162,999..163,373] → 159,530 ops/sec [158,324..160,742] 🔴 -2.2% 93,880 ops/sec [93,671..94,190] → 85,201 ops/sec [84,513..86,045] 🔴 -9.2%
swap variables 483,109 ops/sec [482,311..486,515] → 487,998 ops/sec [478,144..492,109] ~ overlap (+1.0%) 332,415 ops/sec [330,960..336,689] → 319,368 ops/sec [317,399..323,518] 🔴 -3.9%
simple object destructuring 298,954 ops/sec [295,718..300,356] → 317,383 ops/sec [316,640..318,323] 🟢 +6.2% 423,628 ops/sec [417,850..423,917] → 414,126 ops/sec [411,961..416,300] 🔴 -2.2%
with defaults 338,345 ops/sec [336,133..340,197] → 345,673 ops/sec [340,525..349,724] 🟢 +2.2% 539,619 ops/sec [532,692..545,432] → 566,974 ops/sec [561,381..571,676] 🟢 +5.1%
with renaming 322,991 ops/sec [319,354..324,963] → 324,253 ops/sec [323,764..327,447] ~ overlap (+0.4%) 447,560 ops/sec [444,727..451,938] → 439,103 ops/sec [436,809..444,883] ~ overlap (-1.9%)
nested object destructuring 147,082 ops/sec [146,296..147,475] → 145,872 ops/sec [144,035..146,656] ~ overlap (-0.8%) 202,089 ops/sec [200,460..204,298] → 193,944 ops/sec [192,071..198,234] 🔴 -4.0%
rest properties 178,998 ops/sec [175,370..180,534] → 185,463 ops/sec [183,901..187,249] 🟢 +3.6% 190,114 ops/sec [188,708..193,616] → 182,059 ops/sec [180,725..182,786] 🔴 -4.2%
object parameter 92,219 ops/sec [90,827..92,744] → 94,290 ops/sec [93,345..95,139] 🟢 +2.2% 143,642 ops/sec [141,884..145,373] → 146,968 ops/sec [145,915..148,284] 🟢 +2.3%
array parameter 118,116 ops/sec [117,994..119,153] → 121,636 ops/sec [121,426..121,882] 🟢 +3.0% 109,835 ops/sec [109,261..111,474] → 102,276 ops/sec [101,345..103,261] 🔴 -6.9%
mixed destructuring in map 31,813 ops/sec [31,588..31,878] → 34,818 ops/sec [34,539..35,309] 🟢 +9.4% 34,356 ops/sec [34,184..34,377] → 34,265 ops/sec [33,955..34,579] ~ overlap (-0.3%)
forEach with array destructuring 61,710 ops/sec [61,261..61,870] → 60,522 ops/sec [60,289..60,789] 🔴 -1.9% 42,377 ops/sec [42,145..42,755] → 43,016 ops/sec [42,376..43,279] ~ overlap (+1.5%)
map with array destructuring 60,789 ops/sec [60,502..60,831] → 60,934 ops/sec [60,591..61,525] ~ overlap (+0.2%) 42,425 ops/sec [41,843..43,024] → 40,094 ops/sec [39,723..40,350] 🔴 -5.5%
filter with array destructuring 63,469 ops/sec [63,246..64,004] → 62,821 ops/sec [57,341..63,683] ~ overlap (-1.0%) 48,793 ops/sec [48,301..49,034] → 47,681 ops/sec [47,053..48,094] 🔴 -2.3%
reduce with array destructuring 69,563 ops/sec [68,992..70,066] → 69,549 ops/sec [68,992..70,677] ~ overlap (-0.0%) 46,192 ops/sec [45,505..47,148] → 44,693 ops/sec [44,383..45,126] 🔴 -3.2%
map with object destructuring 70,634 ops/sec [70,183..70,903] → 76,938 ops/sec [76,277..77,235] 🟢 +8.9% 86,487 ops/sec [84,534..86,989] → 90,118 ops/sec [89,842..90,293] 🟢 +4.2%
map with nested destructuring 59,115 ops/sec [58,556..59,519] → 64,385 ops/sec [63,128..64,510] 🟢 +8.9% 80,221 ops/sec [79,332..81,137] → 85,652 ops/sec [84,483..86,493] 🟢 +6.8%
map with rest in destructuring 40,929 ops/sec [40,265..41,292] → 40,490 ops/sec [39,792..41,288] ~ overlap (-1.1%) 24,267 ops/sec [24,117..24,403] → 22,938 ops/sec [22,907..23,088] 🔴 -5.5%
map with defaults in destructuring 54,925 ops/sec [54,574..55,526] → 58,382 ops/sec [57,862..58,806] 🟢 +6.3% 61,549 ops/sec [60,390..63,198] → 67,451 ops/sec [66,677..67,885] 🟢 +9.6%
fibonacci.js — Interp: 🟢 4, 4 unch. · avg +4.5% · Bytecode: 🟢 6, 2 unch. · avg +4.0%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 310 ops/sec [307..314] → 334 ops/sec [332..339] 🟢 +7.8% 796 ops/sec [794..800] → 864 ops/sec [860..870] 🟢 +8.5%
recursive fib(20) 28 ops/sec [28..28] → 31 ops/sec [30..31] 🟢 +9.7% 72 ops/sec [72..72] → 77 ops/sec [77..77] 🟢 +7.2%
recursive fib(15) typed 313 ops/sec [310..316] → 336 ops/sec [335..338] 🟢 +7.5% 828 ops/sec [822..832] → 891 ops/sec [890..893] 🟢 +7.7%
recursive fib(20) typed 28 ops/sec [28..28] → 31 ops/sec [30..31] 🟢 +9.5% 76 ops/sec [76..76] → 79 ops/sec [79..79] 🟢 +4.1%
iterative fib(20) via reduce 11,715 ops/sec [11,677..11,780] → 11,795 ops/sec [11,659..12,010] ~ overlap (+0.7%) 17,706 ops/sec [17,518..17,796] → 18,132 ops/sec [18,047..18,238] 🟢 +2.4%
iterator fib(20) 9,419 ops/sec [9,319..9,467] → 9,307 ops/sec [9,244..9,400] ~ overlap (-1.2%) 18,220 ops/sec [18,070..18,437] → 17,821 ops/sec [17,419..18,199] ~ overlap (-2.2%)
iterator fib(20) via Iterator.from + take 15,165 ops/sec [15,093..15,311] → 15,117 ops/sec [15,004..15,240] ~ overlap (-0.3%) 20,307 ops/sec [20,041..20,341] → 21,067 ops/sec [20,899..21,209] 🟢 +3.7%
iterator fib(20) last value via reduce 11,264 ops/sec [11,154..11,382] → 11,555 ops/sec [11,362..11,637] ~ overlap (+2.6%) 14,319 ops/sec [14,130..14,384] → 14,384 ops/sec [14,285..14,454] ~ overlap (+0.5%)
for-of.js — Interp: 7 unch. · avg -1.1% · Bytecode: 🟢 4, 🔴 1, 2 unch. · avg +1.8%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 44,596 ops/sec [44,235..44,791] → 44,136 ops/sec [43,483..44,783] ~ overlap (-1.0%) 161,082 ops/sec [159,615..161,736] → 165,935 ops/sec [164,533..167,624] 🟢 +3.0%
for...of with 100-element array 5,145 ops/sec [5,050..5,160] → 5,063 ops/sec [5,030..5,069] ~ overlap (-1.6%) 17,487 ops/sec [17,240..17,518] → 17,893 ops/sec [17,773..17,948] 🟢 +2.3%
for...of with string (10 chars) 32,784 ops/sec [32,168..33,213] → 32,574 ops/sec [32,457..32,938] ~ overlap (-0.6%) 82,164 ops/sec [81,483..82,547] → 88,329 ops/sec [87,390..89,333] 🟢 +7.5%
for...of with Set (10 elements) 44,326 ops/sec [44,002..44,527] → 43,419 ops/sec [43,074..44,252] ~ overlap (-2.0%) 151,441 ops/sec [149,891..152,379] → 154,168 ops/sec [149,964..156,144] ~ overlap (+1.8%)
for...of with Map entries (10 entries) 28,653 ops/sec [28,308..28,801] → 28,433 ops/sec [27,910..28,901] ~ overlap (-0.8%) 27,246 ops/sec [27,109..27,683] → 26,789 ops/sec [26,480..27,123] ~ overlap (-1.7%)
for...of with destructuring 38,158 ops/sec [37,993..38,252] → 38,256 ops/sec [37,980..38,433] ~ overlap (+0.3%) 35,834 ops/sec [35,548..36,400] → 34,961 ops/sec [34,364..35,271] 🔴 -2.4%
for-await-of with sync array 42,642 ops/sec [42,254..43,031] → 41,941 ops/sec [41,105..42,586] ~ overlap (-1.6%) 122,782 ops/sec [122,209..123,489] → 125,431 ops/sec [124,896..125,957] 🟢 +2.2%
helpers/bench-module.js — Interp: 0 · Bytecode: 0
Benchmark Interpreted Δ Bytecode Δ
iterators.js — Interp: 🟢 10, 10 unch. · avg +1.7% · Bytecode: 🟢 15, 🔴 1, 4 unch. · avg +4.1%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 14,963 ops/sec [14,866..15,051] → 15,241 ops/sec [15,025..15,326] ~ overlap (+1.9%) 19,974 ops/sec [19,899..20,124] → 20,158 ops/sec [19,936..20,386] ~ overlap (+0.9%)
Iterator.from({next}).toArray() — 50 elements 6,494 ops/sec [6,412..6,587] → 6,541 ops/sec [6,504..6,570] ~ overlap (+0.7%) 9,294 ops/sec [9,264..9,371] → 9,619 ops/sec [9,567..9,712] 🟢 +3.5%
spread pre-wrapped iterator — 20 elements 11,145 ops/sec [11,085..11,236] → 11,074 ops/sec [11,038..11,104] ~ overlap (-0.6%) 19,566 ops/sec [19,364..19,713] → 20,194 ops/sec [19,951..20,444] 🟢 +3.2%
Iterator.from({next}).forEach — 50 elements 4,480 ops/sec [4,426..4,513] → 4,597 ops/sec [4,582..4,615] 🟢 +2.6% 5,359 ops/sec [5,310..5,372] → 5,776 ops/sec [5,746..5,818] 🟢 +7.8%
Iterator.from({next}).reduce — 50 elements 4,548 ops/sec [4,499..4,573] → 4,632 ops/sec [4,512..4,670] ~ overlap (+1.8%) 4,963 ops/sec [4,943..4,983] → 5,545 ops/sec [5,530..5,587] 🟢 +11.7%
wrap array iterator 158,974 ops/sec [158,414..159,547] → 160,336 ops/sec [157,344..160,559] ~ overlap (+0.9%) 176,104 ops/sec [174,521..176,987] → 183,670 ops/sec [183,147..187,123] 🟢 +4.3%
wrap plain {next()} object 10,417 ops/sec [10,195..10,594] → 10,530 ops/sec [10,444..10,560] ~ overlap (+1.1%) 14,162 ops/sec [14,058..14,226] → 15,040 ops/sec [14,927..15,272] 🟢 +6.2%
map + toArray (50 elements) 4,546 ops/sec [4,538..4,550] → 4,629 ops/sec [4,578..4,657] 🟢 +1.8% 6,032 ops/sec [6,006..6,061] → 6,303 ops/sec [6,133..6,323] 🟢 +4.5%
filter + toArray (50 elements) 4,416 ops/sec [4,313..4,456] → 4,501 ops/sec [4,477..4,520] 🟢 +1.9% 5,711 ops/sec [5,656..5,741] → 6,135 ops/sec [6,116..6,171] 🟢 +7.4%
take(10) + toArray (50 element source) 26,875 ops/sec [26,720..27,110] → 27,293 ops/sec [27,136..27,358] 🟢 +1.6% 35,365 ops/sec [35,093..35,643] → 36,521 ops/sec [36,239..36,960] 🟢 +3.3%
drop(40) + toArray (50 element source) 6,567 ops/sec [6,484..6,624] → 6,546 ops/sec [6,509..6,571] ~ overlap (-0.3%) 9,063 ops/sec [8,956..9,127] → 9,136 ops/sec [9,090..9,189] ~ overlap (+0.8%)
chained map + filter + take (100 element source) 8,037 ops/sec [7,922..8,074] → 8,241 ops/sec [8,206..8,316] 🟢 +2.5% 10,025 ops/sec [9,912..10,121] → 11,028 ops/sec [10,968..11,128] 🟢 +10.0%
some + every (50 elements) 2,583 ops/sec [2,561..2,604] → 2,640 ops/sec [2,635..2,650] 🟢 +2.2% 3,506 ops/sec [3,466..3,570] → 3,668 ops/sec [3,647..3,714] 🟢 +4.6%
find (50 elements) 5,624 ops/sec [5,564..5,662] → 5,698 ops/sec [5,686..5,724] 🟢 +1.3% 6,947 ops/sec [6,898..7,021] → 7,218 ops/sec [7,168..7,253] 🟢 +3.9%
array.values().map().filter().toArray() 7,599 ops/sec [7,532..7,736] → 8,194 ops/sec [8,071..8,266] 🟢 +7.8% 9,629 ops/sec [9,588..9,718] → 10,203 ops/sec [10,117..10,238] 🟢 +6.0%
array.values().take(5).toArray() 209,529 ops/sec [208,607..210,270] → 208,992 ops/sec [207,353..210,600] ~ overlap (-0.3%) 229,815 ops/sec [224,476..232,326] → 238,136 ops/sec [236,281..239,948] 🟢 +3.6%
array.values().drop(45).toArray() 193,202 ops/sec [192,162..193,692] → 194,730 ops/sec [193,354..196,434] ~ overlap (+0.8%) 207,528 ops/sec [205,121..213,511] → 220,120 ops/sec [218,197..221,857] 🟢 +6.1%
map.entries() chained helpers 9,669 ops/sec [9,462..9,773] → 9,997 ops/sec [9,818..10,100] 🟢 +3.4% 6,140 ops/sec [5,998..6,189] → 5,818 ops/sec [5,784..5,909] 🔴 -5.2%
set.values() chained helpers 16,518 ops/sec [16,340..16,754] → 16,947 ops/sec [16,939..17,081] 🟢 +2.6% 19,397 ops/sec [19,190..19,732] → 19,351 ops/sec [19,237..19,471] ~ overlap (-0.2%)
string iterator map + toArray 13,203 ops/sec [13,101..13,309] → 13,176 ops/sec [13,069..13,231] ~ overlap (-0.2%) 14,099 ops/sec [13,697..14,295] → 14,060 ops/sec [13,920..14,185] ~ overlap (-0.3%)
json.js — Interp: 🟢 18, 2 unch. · avg +4.7% · Bytecode: 🟢 20 · avg +6.8%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 148,831 ops/sec [147,218..149,767] → 155,437 ops/sec [154,597..156,587] 🟢 +4.4% 152,407 ops/sec [151,244..154,211] → 158,670 ops/sec [157,547..160,388] 🟢 +4.1%
parse nested object 94,456 ops/sec [93,411..95,115] → 97,076 ops/sec [96,433..97,689] 🟢 +2.8% 96,334 ops/sec [95,794..97,276] → 101,242 ops/sec [99,155..101,497] 🟢 +5.1%
parse array of objects 55,119 ops/sec [55,023..55,516] → 55,884 ops/sec [55,832..55,984] 🟢 +1.4% 56,877 ops/sec [56,680..57,062] → 57,604 ops/sec [57,220..57,824] 🟢 +1.3%
parse large flat object 59,841 ops/sec [59,684..60,231] → 59,732 ops/sec [59,387..60,141] ~ overlap (-0.2%) 62,372 ops/sec [61,882..63,104] → 65,323 ops/sec [64,203..65,644] 🟢 +4.7%
parse mixed types 67,512 ops/sec [66,999..67,918] → 70,711 ops/sec [70,304..71,093] 🟢 +4.7% 70,344 ops/sec [69,904..70,953] → 74,505 ops/sec [72,724..74,866] 🟢 +5.9%
stringify simple object 151,118 ops/sec [150,316..154,303] → 158,378 ops/sec [157,200..160,060] 🟢 +4.8% 155,346 ops/sec [153,684..156,724] → 168,768 ops/sec [166,107..169,546] 🟢 +8.6%
stringify nested object 82,401 ops/sec [82,001..82,894] → 87,321 ops/sec [86,248..88,378] 🟢 +6.0% 84,169 ops/sec [83,861..84,544] → 91,456 ops/sec [90,067..91,496] 🟢 +8.7%
stringify array of objects 36,642 ops/sec [36,259..36,749] → 39,731 ops/sec [38,930..39,861] 🟢 +8.4% 36,869 ops/sec [36,827..36,999] → 40,082 ops/sec [39,931..40,294] 🟢 +8.7%
stringify mixed types 62,910 ops/sec [62,455..63,190] → 66,844 ops/sec [66,553..67,097] 🟢 +6.3% 64,181 ops/sec [63,945..64,596] → 67,118 ops/sec [66,853..67,633] 🟢 +4.6%
reviver doubles numbers 45,311 ops/sec [44,334..45,869] → 47,506 ops/sec [46,408..48,074] 🟢 +4.8% 48,479 ops/sec [47,836..48,593] → 51,835 ops/sec [51,597..55,029] 🟢 +6.9%
reviver filters properties 38,557 ops/sec [38,442..38,759] → 41,192 ops/sec [40,983..41,807] 🟢 +6.8% 40,435 ops/sec [40,290..40,608] → 43,977 ops/sec [43,664..44,452] 🟢 +8.8%
reviver on nested object 49,566 ops/sec [48,959..50,074] → 51,524 ops/sec [50,774..51,651] 🟢 +4.0% 51,004 ops/sec [49,649..51,472] → 55,332 ops/sec [54,747..55,952] 🟢 +8.5%
reviver on array 30,330 ops/sec [29,687..30,583] → 30,903 ops/sec [29,804..31,057] ~ overlap (+1.9%) 30,883 ops/sec [30,616..31,165] → 33,021 ops/sec [32,762..33,309] 🟢 +6.9%
replacer function doubles numbers 39,627 ops/sec [39,300..39,815] → 42,212 ops/sec [41,916..42,544] 🟢 +6.5% 43,495 ops/sec [42,768..44,378] → 46,800 ops/sec [46,602..46,957] 🟢 +7.6%
replacer function excludes properties 53,106 ops/sec [52,690..53,756] → 55,713 ops/sec [55,286..56,314] 🟢 +4.9% 55,491 ops/sec [55,162..56,017] → 60,207 ops/sec [57,943..60,704] 🟢 +8.5%
array replacer (allowlist) 90,032 ops/sec [89,566..90,356] → 93,905 ops/sec [92,548..95,351] 🟢 +4.3% 94,380 ops/sec [94,160..94,980] → 98,531 ops/sec [98,437..98,809] 🟢 +4.4%
stringify with 2-space indent 72,813 ops/sec [71,861..73,226] → 76,459 ops/sec [76,397..76,526] 🟢 +5.0% 75,094 ops/sec [74,632..75,330] → 81,043 ops/sec [80,038..82,899] 🟢 +7.9%
stringify with tab indent 73,531 ops/sec [72,793..74,071] → 77,224 ops/sec [76,787..77,659] 🟢 +5.0% 76,295 ops/sec [75,160..77,206] → 80,674 ops/sec [79,924..80,947] 🟢 +5.7%
parse then stringify 43,730 ops/sec [43,217..44,024] → 46,493 ops/sec [46,204..46,920] 🟢 +6.3% 45,354 ops/sec [45,170..45,916] → 49,546 ops/sec [48,865..49,647] 🟢 +9.2%
stringify then parse 25,583 ops/sec [25,445..25,800] → 27,236 ops/sec [27,011..27,254] 🟢 +6.5% 26,314 ops/sec [26,153..26,339] → 28,932 ops/sec [28,652..29,602] 🟢 +9.9%
jsx.jsx — Interp: 🟢 13, 8 unch. · avg +2.1% · Bytecode: 🟢 4, 🔴 8, 9 unch. · avg -0.5%
Benchmark Interpreted Δ Bytecode Δ
simple element 207,390 ops/sec [204,787..208,346] → 214,999 ops/sec [213,418..215,250] 🟢 +3.7% 315,298 ops/sec [312,517..325,433] → 315,598 ops/sec [313,740..316,903] ~ overlap (+0.1%)
self-closing element 215,822 ops/sec [209,730..217,772] → 219,845 ops/sec [219,265..221,204] 🟢 +1.9% 342,413 ops/sec [336,235..344,239] → 349,086 ops/sec [346,512..354,451] 🟢 +1.9%
element with string attribute 171,251 ops/sec [169,682..173,121] → 177,659 ops/sec [176,887..178,681] 🟢 +3.7% 263,009 ops/sec [262,214..263,881] → 254,396 ops/sec [253,955..255,279] 🔴 -3.3%
element with multiple attributes 152,186 ops/sec [150,804..153,161] → 155,143 ops/sec [153,678..156,139] 🟢 +1.9% 203,994 ops/sec [201,439..208,902] → 203,743 ops/sec [201,908..206,896] ~ overlap (-0.1%)
element with expression attribute 162,765 ops/sec [161,149..162,984] → 166,633 ops/sec [165,908..167,305] 🟢 +2.4% 254,359 ops/sec [251,275..255,835] → 245,467 ops/sec [244,172..246,154] 🔴 -3.5%
text child 207,940 ops/sec [206,823..209,669] → 207,712 ops/sec [204,229..210,322] ~ overlap (-0.1%) 314,856 ops/sec [312,612..315,972] → 322,177 ops/sec [320,514..326,482] 🟢 +2.3%
expression child 203,700 ops/sec [202,255..205,684] → 203,690 ops/sec [198,783..205,487] ~ overlap (-0.0%) 317,840 ops/sec [315,912..320,634] → 311,809 ops/sec [311,032..315,353] 🔴 -1.9%
mixed text and expression 192,050 ops/sec [188,445..192,672] → 191,802 ops/sec [191,124..192,321] ~ overlap (-0.1%) 282,334 ops/sec [278,264..283,059] → 289,488 ops/sec [286,795..292,783] 🟢 +2.5%
nested elements (3 levels) 79,264 ops/sec [78,389..79,649] → 81,039 ops/sec [80,711..81,727] 🟢 +2.2% 124,282 ops/sec [123,521..126,249] → 121,088 ops/sec [120,178..121,658] 🔴 -2.6%
sibling children 57,894 ops/sec [57,791..58,233] → 60,477 ops/sec [60,026..60,703] 🟢 +4.5% 87,497 ops/sec [85,588..87,874] → 90,455 ops/sec [89,993..90,751] 🟢 +3.4%
component element 146,641 ops/sec [145,452..148,057] → 151,040 ops/sec [150,122..151,698] 🟢 +3.0% 228,263 ops/sec [227,740..230,942] → 219,259 ops/sec [218,099..219,608] 🔴 -3.9%
component with children 90,805 ops/sec [90,134..91,271] → 93,097 ops/sec [92,444..93,791] 🟢 +2.5% 133,717 ops/sec [130,166..135,657] → 136,714 ops/sec [122,328..138,156] ~ overlap (+2.2%)
dotted component 122,726 ops/sec [120,617..124,396] → 124,925 ops/sec [124,164..125,610] ~ overlap (+1.8%) 176,634 ops/sec [175,390..178,258] → 167,294 ops/sec [166,478..169,966] 🔴 -5.3%
empty fragment 213,252 ops/sec [212,760..214,390] → 219,436 ops/sec [217,161..221,403] 🟢 +2.9% 370,283 ops/sec [368,994..370,675] → 370,791 ops/sec [369,128..373,058] ~ overlap (+0.1%)
fragment with children 57,244 ops/sec [57,152..57,331] → 59,646 ops/sec [59,436..59,923] 🟢 +4.2% 90,814 ops/sec [90,359..91,198] → 89,064 ops/sec [88,787..90,030] 🔴 -1.9%
spread attributes 106,790 ops/sec [106,512..107,535] → 107,653 ops/sec [106,623..109,210] ~ overlap (+0.8%) 132,936 ops/sec [130,208..136,068] → 136,936 ops/sec [134,963..138,421] ~ overlap (+3.0%)
spread with overrides 91,847 ops/sec [91,656..92,351] → 96,015 ops/sec [94,716..97,501] 🟢 +4.5% 116,778 ops/sec [113,986..118,564] → 116,722 ops/sec [115,319..117,488] ~ overlap (-0.0%)
shorthand props 155,425 ops/sec [154,887..156,595] → 157,550 ops/sec [156,084..158,764] ~ overlap (+1.4%) 234,032 ops/sec [230,087..236,334] → 234,592 ops/sec [232,686..237,421] ~ overlap (+0.2%)
nav bar structure 26,765 ops/sec [26,545..26,830] → 27,153 ops/sec [26,845..27,570] 🟢 +1.4% 40,114 ops/sec [39,949..40,125] → 39,871 ops/sec [39,593..40,369] ~ overlap (-0.6%)
card component tree 31,030 ops/sec [30,262..31,275] → 31,555 ops/sec [30,978..31,748] ~ overlap (+1.7%) 45,351 ops/sec [45,031..45,789] → 45,063 ops/sec [44,790..45,414] ~ overlap (-0.6%)
10 list items via Array.from 14,328 ops/sec [14,266..14,338] → 14,426 ops/sec [14,239..14,560] ~ overlap (+0.7%) 19,331 ops/sec [19,232..19,597] → 18,805 ops/sec [18,598..19,006] 🔴 -2.7%
modules.js — Interp: 🟢 8, 🔴 1 · avg +5.6% · Bytecode: 🟢 3, 🔴 1, 5 unch. · avg +0.4%
Benchmark Interpreted Δ Bytecode Δ
call imported function 454,041 ops/sec [445,746..459,242] → 477,332 ops/sec [471,870..479,386] 🟢 +5.1% 639,854 ops/sec [637,919..645,347] → 659,152 ops/sec [649,673..665,876] 🟢 +3.0%
call two imported functions 252,515 ops/sec [249,461..255,214] → 267,284 ops/sec [266,058..270,403] 🟢 +5.8% 344,776 ops/sec [342,268..346,067] → 353,421 ops/sec [350,752..355,919] 🟢 +2.5%
read imported constant 1,550,653 ops/sec [1,544,586..1,563,158] → 1,678,251 ops/sec [1,665,736..1,685,011] 🟢 +8.2% 3,650,956 ops/sec [3,636,846..3,654,059] → 3,607,636 ops/sec [3,596,369..3,610,187] 🔴 -1.2%
read imported string 1,537,755 ops/sec [1,523,451..1,541,631] → 1,623,753 ops/sec [1,616,564..1,635,280] 🟢 +5.6% 3,637,463 ops/sec [3,632,388..3,640,017] → 3,639,786 ops/sec [3,628,849..3,654,370] ~ overlap (+0.1%)
read JSON string property 1,560,339 ops/sec [1,553,872..1,570,032] → 1,668,434 ops/sec [1,665,172..1,676,824] 🟢 +6.9% 3,653,875 ops/sec [3,643,459..3,658,232] → 3,628,700 ops/sec [3,599,308..3,666,503] ~ overlap (-0.7%)
read JSON number property 1,530,388 ops/sec [1,520,285..1,542,856] → 1,616,690 ops/sec [1,602,867..1,631,553] 🟢 +5.6% 3,654,644 ops/sec [3,642,907..3,655,549] → 3,636,504 ops/sec [3,570,369..3,652,928] ~ overlap (-0.5%)
read JSON boolean property 1,552,445 ops/sec [1,548,315..1,557,829] → 1,673,253 ops/sec [1,666,538..1,678,478] 🟢 +7.8% 3,619,798 ops/sec [3,607,875..3,631,537] → 3,631,054 ops/sec [3,613,000..3,654,456] ~ overlap (+0.3%)
read JSON array property 1,559,065 ops/sec [1,544,535..1,564,526] → 1,665,302 ops/sec [1,659,387..1,689,738] 🟢 +6.8% 3,637,755 ops/sec [3,628,870..3,640,828] → 3,619,243 ops/sec [3,596,787..3,701,355] ~ overlap (-0.5%)
read multiple JSON properties 930,043 ops/sec [926,483..941,662] → 916,388 ops/sec [912,306..919,774] 🔴 -1.5% 3,290,820 ops/sec [3,283,932..3,293,508] → 3,316,611 ops/sec [3,314,324..3,322,348] 🟢 +0.8%
numbers.js — Interp: 🟢 9, 2 unch. · avg +6.4% · Bytecode: 🟢 8, 🔴 2, 1 unch. · avg +3.3%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 496,963 ops/sec [493,549..505,807] → 527,815 ops/sec [513,311..529,160] 🟢 +6.2% 1,509,036 ops/sec [1,434,063..1,515,544] → 1,061,545 ops/sec [1,059,046..1,062,229] 🔴 -29.7%
floating point arithmetic 592,503 ops/sec [586,762..595,801] → 589,089 ops/sec [583,488..590,760] ~ overlap (-0.6%) 911,938 ops/sec [906,968..914,602] → 766,865 ops/sec [761,491..770,604] 🔴 -15.9%
number coercion 180,344 ops/sec [179,259..184,395] → 193,840 ops/sec [192,794..196,278] 🟢 +7.5% 216,804 ops/sec [215,933..217,244] → 248,592 ops/sec [246,582..249,332] 🟢 +14.7%
toFixed 100,836 ops/sec [99,792..102,009] → 103,900 ops/sec [103,626..104,271] 🟢 +3.0% 113,475 ops/sec [112,028..113,952] → 114,913 ops/sec [114,690..115,094] 🟢 +1.3%
toString 151,181 ops/sec [150,604..151,700] → 158,892 ops/sec [156,876..160,108] 🟢 +5.1% 188,855 ops/sec [184,603..194,369] → 190,734 ops/sec [190,381..192,077] ~ overlap (+1.0%)
valueOf 228,196 ops/sec [227,206..229,339] → 231,986 ops/sec [224,267..235,517] ~ overlap (+1.7%) 249,582 ops/sec [246,422..250,440] → 274,558 ops/sec [272,822..275,358] 🟢 +10.0%
toPrecision 141,020 ops/sec [140,489..141,844] → 145,371 ops/sec [142,970..145,950] 🟢 +3.1% 164,541 ops/sec [161,688..165,237] → 166,698 ops/sec [165,732..169,898] 🟢 +1.3%
Number.isNaN 307,241 ops/sec [306,102..307,846] → 334,141 ops/sec [330,710..336,257] 🟢 +8.8% 312,711 ops/sec [307,910..312,997] → 350,277 ops/sec [348,170..356,038] 🟢 +12.0%
Number.isFinite 295,725 ops/sec [293,675..297,755] → 338,141 ops/sec [332,941..341,061] 🟢 +14.3% 294,104 ops/sec [293,329..294,845] → 341,536 ops/sec [337,943..342,976] 🟢 +16.1%
Number.isInteger 312,293 ops/sec [309,718..315,353] → 346,080 ops/sec [341,403..349,336] 🟢 +10.8% 317,296 ops/sec [316,111..318,960] → 357,352 ops/sec [356,823..357,697] 🟢 +12.6%
Number.parseInt and parseFloat 245,050 ops/sec [243,502..247,802] → 271,773 ops/sec [270,804..273,879] 🟢 +10.9% 242,415 ops/sec [241,428..243,320] → 272,420 ops/sec [270,520..272,948] 🟢 +12.4%
objects.js — Interp: 🟢 6, 🔴 1 · avg +3.1% · Bytecode: 🟢 2, 🔴 2, 3 unch. · avg +1.5%
Benchmark Interpreted Δ Bytecode Δ
create simple object 452,588 ops/sec [448,332..456,255] → 463,374 ops/sec [458,956..469,226] 🟢 +2.4% 584,068 ops/sec [577,632..595,359] → 600,914 ops/sec [594,062..608,244] ~ overlap (+2.9%)
create nested object 223,714 ops/sec [222,946..225,544] → 216,782 ops/sec [214,015..219,564] 🔴 -3.1% 257,093 ops/sec [253,265..259,129] → 246,515 ops/sec [242,728..248,094] 🔴 -4.1%
create 50 objects via Array.from 9,097 ops/sec [9,074..9,121] → 9,151 ops/sec [9,124..9,164] 🟢 +0.6% 9,825 ops/sec [9,764..9,923] → 10,344 ops/sec [10,252..10,426] 🟢 +5.3%
property read 524,219 ops/sec [523,469..525,205] → 560,992 ops/sec [558,419..568,411] 🟢 +7.0% 410,023 ops/sec [402,591..410,549] → 428,802 ops/sec [383,280..436,798] ~ overlap (+4.6%)
Object.keys 266,235 ops/sec [265,304..267,973] → 287,201 ops/sec [283,196..290,675] 🟢 +7.9% 306,405 ops/sec [301,082..307,232] → 318,370 ops/sec [315,703..319,344] 🟢 +3.9%
Object.entries 102,422 ops/sec [102,087..102,948] → 104,396 ops/sec [103,524..105,621] 🟢 +1.9% 111,321 ops/sec [110,955..112,351] → 109,532 ops/sec [106,400..110,617] 🔴 -1.6%
spread operator 168,952 ops/sec [167,363..169,834] → 177,022 ops/sec [175,674..178,148] 🟢 +4.8% 211,768 ops/sec [210,194..214,035] → 210,318 ops/sec [208,539..213,316] ~ overlap (-0.7%)
promises.js — Interp: 🟢 9, 3 unch. · avg +2.2% · Bytecode: 🟢 11, 1 unch. · avg +4.0%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 516,384 ops/sec [512,299..519,020] → 535,378 ops/sec [533,577..539,829] 🟢 +3.7% 541,574 ops/sec [534,395..545,633] → 581,465 ops/sec [578,814..584,156] 🟢 +7.4%
new Promise(resolve => resolve(value)) 186,611 ops/sec [185,387..187,608] → 190,259 ops/sec [189,599..190,408] 🟢 +2.0% 223,981 ops/sec [223,243..226,459] → 230,617 ops/sec [229,561..230,903] 🟢 +3.0%
Promise.reject(reason) 526,229 ops/sec [523,693..527,569] → 542,848 ops/sec [538,144..545,078] 🟢 +3.2% 526,153 ops/sec [523,248..530,937] → 563,299 ops/sec [557,963..568,650] 🟢 +7.1%
resolve + then (1 handler) 169,457 ops/sec [167,671..170,181] → 173,475 ops/sec [172,624..176,350] 🟢 +2.4% 198,355 ops/sec [194,898..200,581] → 205,676 ops/sec [203,735..208,380] 🟢 +3.7%
resolve + then chain (3 deep) 67,008 ops/sec [66,457..67,643] → 68,907 ops/sec [68,828..69,313] 🟢 +2.8% 77,302 ops/sec [76,376..77,740] → 81,597 ops/sec [81,234..82,630] 🟢 +5.6%
resolve + then chain (10 deep) 21,044 ops/sec [20,675..21,176] → 21,431 ops/sec [21,248..22,111] 🟢 +1.8% 24,832 ops/sec [24,556..25,079] → 25,864 ops/sec [25,546..26,205] 🟢 +4.2%
reject + catch + then 95,789 ops/sec [95,326..96,456] → 97,297 ops/sec [96,620..97,441] 🟢 +1.6% 108,525 ops/sec [106,784..109,259] → 115,255 ops/sec [114,355..116,251] 🟢 +6.2%
resolve + finally + then 81,023 ops/sec [80,841..81,059] → 83,166 ops/sec [82,483..83,618] 🟢 +2.6% 92,284 ops/sec [91,819..92,705] → 93,897 ops/sec [93,518..94,023] 🟢 +1.7%
Promise.all (5 resolved) 30,222 ops/sec [30,169..30,416] → 30,865 ops/sec [30,626..31,035] 🟢 +2.1% 32,617 ops/sec [32,312..32,726] → 33,432 ops/sec [33,203..33,854] 🟢 +2.5%
Promise.race (5 resolved) 32,169 ops/sec [31,812..32,785] → 33,143 ops/sec [32,773..33,201] ~ overlap (+3.0%) 34,976 ops/sec [34,709..35,102] → 36,129 ops/sec [35,874..36,428] 🟢 +3.3%
Promise.allSettled (5 mixed) 25,817 ops/sec [25,571..26,038] → 26,103 ops/sec [25,941..26,378] ~ overlap (+1.1%) 27,669 ops/sec [27,477..27,803] → 27,708 ops/sec [27,546..27,964] ~ overlap (+0.1%)
Promise.any (5 mixed) 30,864 ops/sec [30,714..31,018] → 30,900 ops/sec [30,382..31,181] ~ overlap (+0.1%) 32,712 ops/sec [32,666..32,852] → 33,746 ops/sec [33,592..33,912] 🟢 +3.2%
regexp.js — Interp: 🟢 6, 🔴 1, 4 unch. · avg +3.5% · Bytecode: 🟢 5, 6 unch. · avg +3.4%
Benchmark Interpreted Δ Bytecode Δ
regex literal creation 151,810 ops/sec [151,028..152,213] → 148,411 ops/sec [148,054..149,789] 🔴 -2.2% 141,914 ops/sec [140,982..142,629] → 139,926 ops/sec [136,787..141,845] ~ overlap (-1.4%)
new RegExp(pattern, flags) 130,316 ops/sec [129,345..131,787] → 130,142 ops/sec [129,844..130,613] ~ overlap (-0.1%) 139,886 ops/sec [135,287..140,930] → 141,741 ops/sec [140,449..143,124] ~ overlap (+1.3%)
RegExp(existingRegex) returns the same regex 682,175 ops/sec [680,383..685,212] → 735,399 ops/sec [733,310..736,996] 🟢 +7.8% 914,394 ops/sec [911,327..915,863] → 1,029,986 ops/sec [1,027,925..1,031,383] 🟢 +12.6%
test() on a global regex 135,738 ops/sec [134,792..136,147] → 148,064 ops/sec [142,543..148,519] 🟢 +9.1% 158,445 ops/sec [155,994..162,351] → 166,152 ops/sec [164,561..166,810] 🟢 +4.9%
exec() with capture groups 117,031 ops/sec [115,860..117,719] → 125,267 ops/sec [124,316..125,593] 🟢 +7.0% 133,451 ops/sec [131,063..137,406] → 135,250 ops/sec [134,739..135,517] ~ overlap (+1.3%)
toString() 463,102 ops/sec [454,798..466,948] → 487,825 ops/sec [481,770..502,309] 🟢 +5.3% 602,052 ops/sec [594,430..606,418] → 654,141 ops/sec [653,681..656,100] 🟢 +8.7%
match() with global regex 38,911 ops/sec [37,667..39,632] → 40,051 ops/sec [39,232..40,761] ~ overlap (+2.9%) 40,299 ops/sec [39,955..40,785] → 40,550 ops/sec [39,976..40,871] ~ overlap (+0.6%)
matchAll() with capture groups 20,039 ops/sec [19,808..20,173] → 20,972 ops/sec [20,894..21,038] 🟢 +4.7% 25,748 ops/sec [25,629..25,874] → 26,383 ops/sec [26,240..26,685] 🟢 +2.5%
replace() with global regex 37,634 ops/sec [36,913..37,902] → 38,269 ops/sec [37,898..38,875] ~ overlap (+1.7%) 39,044 ops/sec [38,206..39,217] → 39,326 ops/sec [38,784..39,672] ~ overlap (+0.7%)
search() with regex 76,267 ops/sec [75,585..76,653] → 77,255 ops/sec [76,593..78,010] ~ overlap (+1.3%) 76,971 ops/sec [76,676..77,324] → 78,348 ops/sec [76,000..79,161] ~ overlap (+1.8%)
split() with regex separator 38,166 ops/sec [37,957..38,398] → 38,758 ops/sec [38,421..39,047] 🟢 +1.6% 39,171 ops/sec [38,928..39,352] → 40,701 ops/sec [40,631..40,797] 🟢 +3.9%
strings.js — Interp: 🟢 6, 🔴 1, 4 unch. · avg +2.3% · Bytecode: 🟢 10, 1 unch. · avg +5.8%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 397,167 ops/sec [395,970..397,367] → 393,436 ops/sec [391,712..396,159] ~ overlap (-0.9%) 288,466 ops/sec [282,342..291,972] → 317,135 ops/sec [315,100..319,999] 🟢 +9.9%
template literal 678,347 ops/sec [669,751..686,728] → 642,441 ops/sec [635,951..651,095] 🔴 -5.3% 615,398 ops/sec [610,536..620,990] → 660,363 ops/sec [649,539..663,454] 🟢 +7.3%
string repeat 393,884 ops/sec [389,261..395,981] → 390,678 ops/sec [386,279..394,433] ~ overlap (-0.8%) 456,596 ops/sec [452,604..461,394] → 472,732 ops/sec [470,076..474,188] 🟢 +3.5%
split and join 128,754 ops/sec [127,128..129,217] → 135,380 ops/sec [133,916..135,875] 🟢 +5.1% 149,245 ops/sec [148,668..149,496] → 153,911 ops/sec [153,687..154,364] 🟢 +3.1%
indexOf and includes 161,749 ops/sec [160,449..163,752] → 169,145 ops/sec [166,191..169,874] 🟢 +4.6% 181,948 ops/sec [180,199..184,518] → 195,889 ops/sec [195,646..196,040] 🟢 +7.7%
toUpperCase and toLowerCase 252,381 ops/sec [249,119..254,616] → 253,897 ops/sec [252,452..257,613] ~ overlap (+0.6%) 325,522 ops/sec [323,449..327,897] → 335,255 ops/sec [332,930..338,622] 🟢 +3.0%
slice and substring 146,615 ops/sec [144,920..147,902] → 156,576 ops/sec [155,327..157,770] 🟢 +6.8% 191,333 ops/sec [190,435..192,590] → 203,939 ops/sec [199,313..205,817] 🟢 +6.6%
trim operations 185,916 ops/sec [183,733..187,620] → 189,934 ops/sec [184,059..191,868] ~ overlap (+2.2%) 240,756 ops/sec [239,429..243,015] → 250,675 ops/sec [248,641..250,793] 🟢 +4.1%
replace and replaceAll 197,397 ops/sec [195,474..199,644] → 203,592 ops/sec [201,377..205,555] 🟢 +3.1% 223,057 ops/sec [221,472..224,817] → 242,951 ops/sec [240,164..243,990] 🟢 +8.9%
startsWith and endsWith 129,651 ops/sec [129,024..132,401] → 134,738 ops/sec [133,609..136,412] 🟢 +3.9% 154,467 ops/sec [153,327..154,550] → 157,695 ops/sec [149,881..165,817] ~ overlap (+2.1%)
padStart and padEnd 185,046 ops/sec [182,396..185,626] → 196,087 ops/sec [194,750..197,360] 🟢 +6.0% 223,164 ops/sec [220,441..224,184] → 240,828 ops/sec [239,516..241,713] 🟢 +7.9%
typed-arrays.js — Interp: 🟢 9, 🔴 7, 6 unch. · avg +0.8% · Bytecode: 🟢 8, 🔴 9, 5 unch. · avg -1.1%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 324,416 ops/sec [322,025..326,064] → 330,344 ops/sec [328,842..332,094] 🟢 +1.8% 366,906 ops/sec [366,321..369,554] → 383,907 ops/sec [381,516..386,695] 🟢 +4.6%
new Int32Array(100) 296,876 ops/sec [293,580..298,208] → 297,362 ops/sec [296,957..299,287] ~ overlap (+0.2%) 331,790 ops/sec [329,824..334,550] → 342,411 ops/sec [339,370..347,763] 🟢 +3.2%
new Int32Array(1000) 177,635 ops/sec [176,250..179,453] → 164,512 ops/sec [163,498..167,535] 🔴 -7.4% 194,153 ops/sec [192,137..196,556] → 177,918 ops/sec [176,357..179,595] 🔴 -8.4%
new Float64Array(100) 268,135 ops/sec [267,134..269,163] → 263,560 ops/sec [252,883..264,162] 🔴 -1.7% 298,501 ops/sec [296,790..300,111] → 295,919 ops/sec [294,458..298,891] ~ overlap (-0.9%)
Int32Array.from([...]) 179,780 ops/sec [179,118..180,686] → 168,899 ops/sec [167,515..169,717] 🔴 -6.1% 189,653 ops/sec [186,945..192,735] → 176,924 ops/sec [175,635..180,136] 🔴 -6.7%
Int32Array.of(1, 2, 3, 4, 5) 298,407 ops/sec [297,797..300,220] → 293,088 ops/sec [288,983..298,094] ~ overlap (-1.8%) 341,752 ops/sec [339,242..344,340] → 355,099 ops/sec [352,666..362,116] 🟢 +3.9%
sequential write 100 elements 3,404 ops/sec [3,391..3,414] → 3,431 ops/sec [3,395..3,438] ~ overlap (+0.8%) 15,209 ops/sec [15,105..15,513] → 15,274 ops/sec [15,216..15,295] ~ overlap (+0.4%)
sequential read 100 elements 3,431 ops/sec [3,414..3,438] → 3,446 ops/sec [3,421..3,476] ~ overlap (+0.4%) 10,355 ops/sec [10,281..10,560] → 10,839 ops/sec [10,620..10,918] 🟢 +4.7%
Float64Array write 100 elements 3,157 ops/sec [3,134..3,201] → 3,164 ops/sec [3,151..3,178] ~ overlap (+0.2%) 11,095 ops/sec [10,828..11,163] → 10,712 ops/sec [10,579..10,819] 🔴 -3.4%
fill(42) 45,303 ops/sec [45,210..45,336] → 45,147 ops/sec [44,997..45,258] ~ overlap (-0.3%) 45,797 ops/sec [45,767..45,849] → 45,408 ops/sec [45,142..46,135] ~ overlap (-0.8%)
slice() 196,917 ops/sec [196,616..197,532] → 190,857 ops/sec [190,114..194,116] 🔴 -3.1% 217,731 ops/sec [216,732..220,421] → 205,565 ops/sec [204,902..206,748] 🔴 -5.6%
map(x => x * 2) 7,467 ops/sec [7,401..7,489] → 7,979 ops/sec [7,955..8,020] 🟢 +6.9% 8,687 ops/sec [8,661..8,746] → 8,801 ops/sec [8,759..8,865] 🟢 +1.3%
filter(x => x > 50) 7,594 ops/sec [7,570..7,677] → 8,270 ops/sec [8,191..8,402] 🟢 +8.9% 9,840 ops/sec [9,626..9,868] → 10,021 ops/sec [9,961..10,063] 🟢 +1.8%
reduce (sum) 7,374 ops/sec [7,348..7,406] → 8,130 ops/sec [7,948..8,148] 🟢 +10.2% 7,628 ops/sec [7,534..7,659] → 7,576 ops/sec [7,503..7,644] ~ overlap (-0.7%)
sort() 169,318 ops/sec [168,739..169,622] → 157,529 ops/sec [157,483..158,042] 🔴 -7.0% 180,265 ops/sec [180,069..180,272] → 164,023 ops/sec [163,583..164,268] 🔴 -9.0%
indexOf() 409,218 ops/sec [407,188..411,265] → 419,745 ops/sec [418,532..420,430] 🟢 +2.6% 483,422 ops/sec [468,390..485,391] → 482,419 ops/sec [481,501..482,665] ~ overlap (-0.2%)
reverse() 313,411 ops/sec [312,527..314,081] → 308,892 ops/sec [307,872..310,043] 🔴 -1.4% 349,869 ops/sec [349,369..350,169] → 335,153 ops/sec [334,816..335,457] 🔴 -4.2%
create view over existing buffer 384,875 ops/sec [383,117..387,210] → 401,131 ops/sec [396,479..402,383] 🟢 +4.2% 439,592 ops/sec [439,046..443,792] → 459,901 ops/sec [452,612..461,537] 🟢 +4.6%
subarray() 404,617 ops/sec [401,183..407,830] → 424,894 ops/sec [422,334..426,336] 🟢 +5.0% 523,828 ops/sec [520,529..525,186] → 514,038 ops/sec [509,586..516,133] 🔴 -1.9%
set() from array 538,520 ops/sec [535,447..539,430] → 575,684 ops/sec [573,444..577,820] 🟢 +6.9% 605,651 ops/sec [603,613..610,131] → 644,589 ops/sec [641,558..645,552] 🟢 +6.4%
for-of loop 4,809 ops/sec [4,792..4,830] → 4,940 ops/sec [4,893..4,967] 🟢 +2.7% 18,423 ops/sec [18,174..18,758] → 17,003 ops/sec [16,906..17,264] 🔴 -7.7%
spread into array 16,989 ops/sec [16,947..17,095] → 16,402 ops/sec [16,310..16,553] 🔴 -3.5% 95,753 ops/sec [94,997..96,804] → 89,860 ops/sec [88,887..90,906] 🔴 -6.2%

Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context.

Add temp-root protection for callbacks stored in FOnTestFinishedCallbacks,
matching the existing pattern used by beforeAll/beforeEach/afterEach/afterAll
hooks. Hoist async test arrays to describe scope so follow-up tests can
assert that cleanup callbacks actually executed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frostney frostney merged commit 7b9c8df into main Apr 8, 2026
9 checks passed
@frostney frostney deleted the t3code/test-lifecycle-coverage branch April 8, 2026 15:12
@frostney frostney added the new feature New feature or request label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant