Skip to content

stream: drop per-chunk Promise alloc in pipeTo - #63572

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
mcollina:stream/pipeto-mark-as-handled
Jun 2, 2026
Merged

stream: drop per-chunk Promise alloc in pipeTo#63572
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
mcollina:stream/pipeto-mark-as-handled

Conversation

@mcollina

@mcollinamcollina commented May 25, 2026

Copy link
Copy Markdown
Member

Replace setPromiseHandled with markPromiseAsHandled at the two pipeTo per-chunk call sites in readablestream.js. The .then(undefined, () => {}) chain that setPromiseHandled allocates per chunk has no observer in pipeTo: errors already propagate through writer.closed (which watchErrored monitors) and the last state.currentWrite is awaited in waitForCurrentWrite during shutdown (markAsHandled does not affect that subsequent .then). The per-chunk chain Promise + noop closure exist solely to silence the unhandled-rejection event: markPromiseAsHandled sets V8's MarkAsHandled + MarkAsSilent flags directly with no allocation.

benchmark/webstreams/pipe-to.js at HWM=1024: ~5% throughput improvement (728K vs 694K ops/s mean, 6 alternating samples), with substantially tighter run-to-run variance.

WPT streams parity preserved: 1403 subtests passing, 0 unexpected failures.

@nodejs-github-botnodejs-github-bot added needs-ci PRs that need a full CI run. web streams labels May 25, 2026
@codecov

codecovBot commented May 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.34%. Comparing base (17e4196) to head (8e65650).
⚠️ Report is 31 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #63572 +/- ##
==========================================
+ Coverage 90.33% 90.34% +0.01% 
==========================================
Files 732 732 Lines 236454 236458 +4 Branches 44540 44530 -10 ==========================================
+ Hits 213589 213635 +46 + Misses 14581 14524 -57 - Partials 8284 8299 +15 
Files with missing linesCoverage Δ
lib/internal/webstreams/readablestream.js98.54% <100.00%> (+<0.01%)⬆️

... and 35 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +1574 to +1582
//
// setPromiseHandled's job here is purely to silence the per-chunk
// unhandled-rejection event — the chain Promise + noop closure it
// would allocate are unobserved by anything else (errors propagate
// through writer.closed, which pipeTo monitors via watchErrored).
// markPromiseAsHandled sets V8's MarkAsHandled + MarkAsSilent flags
// directly, with no per-chunk allocation. The LAST state.currentWrite
// is awaited in waitForCurrentWrite during shutdown — markAsHandled
// does not affect that subsequent .then chain.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think this comment will make much sense after this PR is merged

Suggested change
//
// setPromiseHandled's job here is purely to silence the per-chunk
// unhandled-rejection event — the chain Promise + noop closure it
// would allocate are unobserved by anything else (errors propagate
// through writer.closed, which pipeTo monitors via watchErrored).
// markPromiseAsHandled sets V8's MarkAsHandled + MarkAsSilent flags
// directly, with no per-chunk allocation. The LAST state.currentWrite
// is awaited in waitForCurrentWrite during shutdown — markAsHandled
// does not affect that subsequent .then chain.

Comment threadlib/internal/webstreams/util.js Outdated
@@ -35,6 +35,7 @@ const {
kPending,
},
getPromiseDetails,
markPromiseAsHandled,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does it really make sense to import it just to re-export it? I don't like it, it makes it harder to realize it crosses the C++ boundary

@aduh95aduh95 added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. request-ci Add this label to start a Jenkins CI on a PR. labels May 28, 2026
@mcollina
mcollinaforce-pushed the stream/pipeto-mark-as-handled branch from 5c8488d to 7932aaeCompareMay 28, 2026 08:58
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label May 28, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@mcollina
mcollinaforce-pushed the stream/pipeto-mark-as-handled branch from 7932aae to 80e3a93CompareMay 28, 2026 15:15
@aduh95aduh95 added the request-ci Add this label to start a Jenkins CI on a PR. label May 28, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label May 28, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@mcollina
mcollinaforce-pushed the stream/pipeto-mark-as-handled branch from 80e3a93 to 9783b9dCompareMay 30, 2026 16:59
Signed-off-by: Matteo Collina <hello@matteocollina.com>
@mcollina
mcollinaforce-pushed the stream/pipeto-mark-as-handled branch from 9783b9d to 8e65650CompareMay 30, 2026 17:02
@aduh95aduh95 added the request-ci Add this label to start a Jenkins CI on a PR. label Jun 2, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jun 2, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@aduh95aduh95 added the commit-queue Add this label to land a pull request using GitHub Actions. label Jun 2, 2026
@nodejs-github-botnodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Jun 2, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 6af9026 into nodejs:mainJun 2, 2026
73 of 75 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 6af9026

@mcollina
mcollina deleted the stream/pipeto-mark-as-handled branch June 8, 2026 13:27
aduh95 pushed a commit that referenced this pull request Jun 18, 2026
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: #63572
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
aduh95 pushed a commit that referenced this pull request Jul 20, 2026
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: #63572
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
aduh95 pushed a commit that referenced this pull request Jul 21, 2026
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: #63572
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
aduh95 pushed a commit that referenced this pull request Jul 22, 2026
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: #63572
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
aduh95 pushed a commit that referenced this pull request Jul 30, 2026
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: #63572
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs that have at least one approval, no pending requests for changes, and a CI started.needs-ciPRs that need a full CI run.web streams

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@mcollina@nodejs-github-bot@aduh95