Skip to content

Fire the "close" event on MessagePort from a task - #12957

Closed
nicolo-ribaudo wants to merge 2 commits into
whatwg:mainfrom
nicolo-ribaudo:messageport-close-fire-from-task
Closed

nicolo-ribaudo wants to merge 2 commits into
whatwg:mainfrom
nicolo-ribaudo:messageport-close-fire-from-task

Conversation

@nicolo-ribaudo

@nicolo-ribaudo nicolo-ribaudo commented Sep 17, 2026 •

Copy link
Copy Markdown
Member

This PR fixes #12797.

Nobody implements MessagePort's close event (see e.g. #10201) so arguably this PR isn't very useful, but currently the spec is in an invalid state where it fires an event without having a clear JS context running.

This patch moves the event to be fired from a task scheduled on the target's message queue, so that:

  • there is no synchronous event fired "while garbage-collecting", which is not a well-define time
  • if portA is in workerA and portB is in workerB, a being closed fires the event in B using B's event loop rather than A's

  • At least two implementers are interested (and none opposed):
    • …
    • …
  • Tests are written and can be reviewed and commented upon at:
    • TODO, I'd like to first get some initial reviews here
  • Implementation bugs are filed:
    • Chromium: …
    • Gecko: …
    • WebKit: …
    • Deno (only for timers, structured clone, base64 utils, channel messaging, module resolution, web workers, and web storage): …
    • Node.js (only for timers, structured clone, base64 utils, channel messaging, and module resolution): …
  • Corresponding HTML AAM & ARIA in HTML issues & PRs:
  • MDN issue is filed: …
  • The top of this comment includes a clear commit message to use.

(See WHATWG Working Mode: Changes for more details.)


/web-messaging.html ( diff )

Comment thread source Outdated

<li><p><span data-x="concept-event-fire">Fire an event</span> named <code
data-x="event-close">close</code> at <var>otherPort</var>.</p></li>
<li><p><span>Queue a global task</span> on the <span>DOM manipulation task source</span> given

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

MessagePorts have a port message queue task source, but using that same task source would be a larger normative change since we'd start requiring that the close event is only fired after that all messages have been processed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think we should use the port message queue task source, and therefore also amending the transfer-receiving steps to explicitly mention "close" events in addition to "message" events when it "Move(s) all the tasks...".

This is because we can transfer a MessagePort that still has several messages in its queue and that has been closed by the other side, and it makes sense for all of those messages and then the close event to be fired wherever that MessagePort ends up and that will be very content-observable (versus the messages transferring but the close event firing on the otherwise dead MessagePort in the transferring global). So I think it's really the only way we can sanely specify it. Hand-wavingly, I think the case can be made that the ambiguity of the current under-specification might imply this, but it's also incredibly ambiguous, so thank you for undertaking this cleanup!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I should also note that while I can only speak from a Gecko perspective, both our current implementation of MessagePorts that used a centralized router model and our/my planned overhaul of MessagePorts that uses direct endpoint connections both favor use of the port message queue task source and re-shipping. I think it would be a somewhat weird IPC model where it would be easier for an implementation to do the global task that wasn't effectively using the port message queue up until the last second.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Changed!

@foolip foolip added the needs implementer interest Moving the issue forward requires implementers to express interest label Sep 29, 2026
@foolip

foolip commented Sep 29, 2026

Copy link
Copy Markdown
Member

I added the "needs implementer interest" label because I expect that will block landing this PR. Or is there implementer interest from @asutherland?

@nicolo-ribaudo

Copy link
Copy Markdown
Member Author

Fwiw if there is no implementer interest for this PR because nobody ships this event, I'd also be happy to open a PR just removing it.

@zcorpan

zcorpan commented Sep 30, 2026

Copy link
Copy Markdown
Member

IMO we can view this PR as a bug fix that doesn't affect current implementations. But there should be bugs filed about supporting the close event. If more time passes and still nobody supports the close event, it should be dropped. I believe @asutherland had some interest in supporting close.

@annevk

annevk commented Sep 30, 2026

Copy link
Copy Markdown
Member

We should just remove this event from the specification until we have a design we are satisfied with. I raised this in 2024 #1766 (comment) and nobody resolved the new issue so I'm not sure why we keep pretending this is good.

@foolip

foolip commented Sep 30, 2026

Copy link
Copy Markdown
Member

If no implementation has shipped the closed event I think it makes sense to first remove it and then open a new PR as if it was new. This way it's easier to review it for what it is, not as a delta against something that was never implemented.

@zcorpan

zcorpan commented Sep 30, 2026

Copy link
Copy Markdown
Member

OK, fair enough.

nicolo-ribaudo added a commit to nicolo-ribaudo/html that referenced this pull request Oct 1, 2026
This is a revert of cc2634f (it's not
a "clean" revert because of some other changes that happened in the
meantime).

This mans that this patch also restores the older GC semantics: a
port is not easily GC-able, it is not exlicitly disentangled when
the other half's owner document is destroyed, and relies on polling to
see if the other half is still alive. I believe this matches Firefox's
behavior, which is also what I believe the discussion in whatwg#10201 leads to.

Note that browsers have all different GC semantics (according to Claude):
- Chromium makes a port uncollectable only if it's already started
- Firefox does not collect them
- WebKit keeps the port uncollectable only if it has a message listener

Given that no browser ships the `close` events this revert is probably
the best thing to do; if somebody in the future wants to reintroduce it
some relevant discussions are:
- whatwg#1766
- whatwg#9933
- whatwg#10201
- whatwg#12797
- whatwg#12957
@nicolo-ribaudo nicolo-ribaudo mentioned this pull request Oct 1, 2026
6 tasks done
@nicolo-ribaudo

Copy link
Copy Markdown
Member Author

I opened #13016. @annevk @foolip Can I consider your comments here as "implementer interest" for removing the event?

nicolo-ribaudo added a commit to nicolo-ribaudo/html that referenced this pull request Oct 1, 2026
This is a revert of cc2634f (it's not
a "clean" revert because of some other changes that happened in the
meantime).

This mans that this patch also restores the older GC semantics: a
port is not easily GC-able, it is not exlicitly disentangled when
the other half's owner document is destroyed, and relies on polling to
see if the other half is still alive. I believe this matches Firefox's
behavior, which is also what I believe the discussion in whatwg#10201 leads to.

Note that browsers have all different GC semantics (according to Claude):
- Chromium makes a port uncollectable only if it's already started
- Firefox does not collect them
- WebKit keeps the port uncollectable only if it has a message listener

Given that no browser ships the `close` events this revert is probably
the best thing to do; if somebody in the future wants to reintroduce it
some relevant discussions are:
- whatwg#1766
- whatwg#9933
- whatwg#10201
- whatwg#12797
- whatwg#12957
nicolo-ribaudo added a commit to nicolo-ribaudo/html that referenced this pull request Oct 1, 2026
This is a revert of cc2634f (it's not
a "clean" revert because of some other changes that happened in the
meantime).

This means that this patch also restores the older GC semantics: a
port is not easily GC-able, it is not explicitly disentangled when
the other half's owner document is destroyed, and relies on polling to
see if the other half is still alive. I believe this matches Firefox's
behavior, which is also what I believe the discussion in whatwg#10201 leads to.

Note that browsers have all different GC semantics (according to Claude):
- Chromium makes a port uncollectable only if it's already started
- Firefox does not collect them
- WebKit keeps the port uncollectable only if it has a message listener

Given that no browser ships the `close` events this revert is probably
the best thing to do; if somebody in the future wants to reintroduce it
some relevant discussions are:
- whatwg#1766
- whatwg#9933
- whatwg#10201
- whatwg#12797
- whatwg#12957
nicolo-ribaudo added a commit to nicolo-ribaudo/html that referenced this pull request Oct 1, 2026
This is a revert of cc2634f (it's not
a "clean" revert because of some other changes that happened in the
meantime).

This means that this patch also restores the older GC semantics: a
port is not easily GC-able, it is not explicitly disentangled when
the other half's owner document is destroyed, and relies on polling to
see if the other half is still alive. I believe this matches Firefox's
behavior, which is also what I believe the discussion in whatwg#10201 leads to.

Note that browsers have all different GC semantics (according to Claude):
- Chromium makes a port uncollectable only if it's already started
- Firefox does not collect them
- WebKit keeps the port uncollectable only if it has a message listener

Given that no browser ships the `close` events this revert is probably
the best thing to do; if somebody in the future wants to reintroduce it
some relevant discussions are:
- whatwg#1766
- whatwg#9933
- whatwg#10201
- whatwg#12797
- whatwg#12957
@zcorpan

zcorpan commented Oct 1, 2026

Copy link
Copy Markdown
Member

Closing this per comments above.

@zcorpan zcorpan closed this Oct 1, 2026
nicolo-ribaudo added a commit to nicolo-ribaudo/html that referenced this pull request Oct 2, 2026
This is a revert of cc2634f (it's not
a "clean" revert because of some other changes that happened in the
meantime).

This means that this patch also restores the older GC semantics: a
port is not easily GC-able, it is not explicitly disentangled when
the other half's owner document is destroyed, and relies on polling to
see if the other half is still alive. I believe this matches Firefox's
behavior, which is also what I believe the discussion in whatwg#10201 leads to.

Note that browsers have all different GC semantics (according to Claude):
- Chromium makes a port uncollectable only if it's already started
- Firefox does not collect them
- WebKit keeps the port uncollectable only if it has a message listener

Given that no browser ships the `close` events this revert is probably
the best thing to do; if somebody in the future wants to reintroduce it
some relevant discussions are:
- whatwg#1766
- whatwg#9933
- whatwg#10201
- whatwg#12797
- whatwg#12957
annevk pushed a commit that referenced this pull request Oct 2, 2026
This is a revert of cc2634f (it's not
a "clean" revert because of some other changes that happened in the
meantime).

This means that this patch also restores the older GC semantics: a
port is not easily GC-able, it is not explicitly disentangled when
the other half's owner document is destroyed, and relies on polling to
see if the other half is still alive. I believe this matches Firefox's
behavior, which is also what I believe the discussion in #10201 leads to.

Note that browsers have all different GC semantics (according to Claude):
- Chromium makes a port uncollectable only if it's already started
- Firefox does not collect them
- WebKit keeps the port uncollectable only if it has a message listener

Given that no browser ships the `close` events this revert is probably
the best thing to do; if somebody in the future wants to reintroduce it
some relevant discussions are:
- #1766
- #9933
- #10201
- #12797
- #12957

Tests: web-platform-tests/wpt#63174

Closes #10201 and closes #12797.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs implementer interest Moving the issue forward requires implementers to express interest

Development

Successfully merging this pull request may close these issues.

MessagePort should probably fire close event from a task

5 participants