前端前線 2026 年 10 月 3 日

2026-10-03 — HTML 規格移除 MessagePort 的 close 事件,GC 語意退回舊版

primary=https://github.com/whatwg/html/commit/5facb53a8b013f209aa789ea0726e404f12c83d9 primary=https://github.com/whatwg/html/issues/10201 primary=https://github.com/whatwg/html/commit/cc2634fed12737f342da865f1f5c4f751c2da601

HTML 規格移除 MessagePort 的 close 事件,GC 語意退回舊版

WHATWG HTML Standard commit 5facb53 · 2026-10-02

HTML 規格把 MessagePort 的 close 事件與 onclose 屬性整個拿掉,等於撤銷 2024 年加入、但沒有任何瀏覽器出貨的「對端關閉通知」。這個 commit 是 Nicolò Ribaudo 在 2026-10-02 提交的 revert,標題為 Remove MessagePort's close event,同時關閉 issue #10201 與 #12797。

連帶被撤銷的還有一套新的垃圾回收(GC)規則,規格文字回到舊版:port 不容易被回收,也不再有「對端被回收就自動斷開」的行為。

原本的問題

兩個互相 entangle 的 MessagePort 中,一端消失時,另一端沒有可靠又即時的方法得知。這是 issue #1766 的核心:持有 port 的程式難以及時釋放與它綁定的資源。

2024-01-12 的commit cc2634f(Add a close event to MessagePort)加入了解法:port A 關閉時,在 port B 上觸發 close。規格說明還指出,即使沒呼叫 close(),只要 Document 被銷毀或 port 被 GC,事件也會觸發。

這個設計很快碰到安全疑慮。issue #10201(2024-03-14 建立)寫明,Chrome 因安全考量不會照規格實作:事件等於把「對端持有者發生過 GC」這個訊號寫進標準,網頁可以藉此觀察另一端的 GC 時機。

核心改動

這次 commit 的 diff 為 source 一個檔案、27 行新增、65 行刪除。刪掉的內容有三塊:

  • IDL 中的 attribute EventHandler onclose,以及事件處理器表格裡的對應列。
  • disentangle 流程最後的 fire an event named close at otherPort 這一步,與說明三種觸發情境的 note。
  • 銷毀 Document 時「對該文件擁有的每個 port 執行 disentangle」的步驟。
- attribute EventHandler onclose;
- Fire an event named close at otherPort.
- For each port in ports, disentangle port.

GC 規則則換回舊寫法:entangled 的 port,user agent 必須視為「對端 port 對它有強參照」,或「它的 relevant global object 對它有強參照」,兩者擇一。新版取消了「被 GC 就 disentangle」與「有 message listener 才保持強參照」的條件式寫法。

加入 close 事件後(2024)本次 revert 後
對端關閉通知在另一端 port 觸發 close無,onclose 不存在
Document 銷毀明確 disentangle 該文件的 port不處理,靠對端自行發現
port 被 GC被 GC 即 disentangleentangled 時須維持強參照

影響範圍

commit message 說明,沒有任何瀏覽器出貨過 close 事件,所以線上行為不會因此改變;真正受影響的是照著規格文字寫程式或實作的人。

  • 依賴 port.onclose 或 addEventListener('close', …) 偵測對端結束的程式碼:本來就無法在主流瀏覽器運作,現在規格也不再承諾,不要把它當作清理資源的唯一依據。
  • 做 broadcast 的程式(把多個 MessagePort 放進陣列逐一送訊息):規格新增一節非規範性的「Broadcasting to many ports」,指出陣列會讓對端已消失的 port 無法被回收。
  • 瀏覽器引擎的實作者:GC 規則回到上述兩選一的強參照寫法,不必再實作由 GC 觸發的 disentangle。

新增的那一節建議的做法是自訂簡單的存活確認協定:對端要回覆自己還在,逾時未回覆就視為消失,主動 close() 該 port,讓它可被回收。

// 規格建議的方向(示意)
// 定期 ping,逾時未收到 ack 就關閉
if (now - lastAck > timeout) port.close();

這段程式只是依規格文字描述的協定所寫的示意,規格並未給出逾時數值。

為何選擇退回

commit message 提到各瀏覽器的 port GC 語意本來就不一致:Chromium 只在 port 已 start 時才讓它不可回收,Firefox 不回收,WebKit 只在有 message listener 時才不可回收。作者表示這個 revert 回到的舊語意,他認為與 Firefox 的行為相符,也是 #10201 討論的走向。

message 也列出日後若要重新提出的相關討論:#1766、#9933、#10201、#12797、#12957。對應的測試在 web-platform-tests 的 #63174;至於該測試的內容,commit 本身未說明。

原始來源:whatwg/html 5facb53、issue #10201、commit cc2634f


End of article
0
Would love your thoughts, please comment.x
()
x