MessageChannel跨域通信需同源,否则postMessage静默丢弃;两端port均须调用start()激活;transfer后原port立即失效;close()不自动清理监听器,须手动移除防泄漏。

MessageChannel 构造函数必须在同源上下文中创建
跨域 iframe 或不同协议(如 http:// 和 https://)之间直接 new MessageChannel() 没问题,但后续调用 port1.postMessage() 时若目标 MessagePort 来自跨域 iframe,浏览器会静默丢弃消息,且不报错。这是最容易被忽略的“没反应”原因。
验证方法:在发送前检查 port2 所属的 window 是否可访问(比如 iframe.contentWindow 存在且非 null),再确认该 window 的 origin 与当前页一致。
- 同源通信是默认安全前提,
MessageChannel本身不解决跨域授权 - 若需跨域,必须配合
window.postMessage()+message事件中转MessagePort(通过event.ports[0]获取) -
MessageChannel实例不能序列化,不可存入 localStorage 或跨 Worker 传递
postMessage 后必须显式调用 start() 才能接收消息
新建的 MessagePort 默认处于 entangled but inactive 状态。即使绑定了 onmessage 或 addEventListener('message', ...),也不触发回调——除非先调用 port.start()。
常见错误是只在主线程 port 上调用 start(),却忘了在 iframe 或 Worker 中接收到的 port2 也得调用一次。漏掉任意一端,消息就卡死。
- Worker 场景下,
self.onmessage收到 port 后,必须立刻event.ports[0].start() - iframe 场景下,父页传入 port 后,子页需在
window.addEventListener('message', e => { e.ports[0].start() })中启动 - Chrome DevTools 的 Application → Frames 面板里能看到 port 的
state字段,active才算就绪
MessagePort 关闭后不可重用,且 close() 不会自动清理监听器
port.close() 是单向终结操作:它让端口进入 closed 状态,之后所有 postMessage() 抛出 DataCloneError,但已注册的 onmessage 或事件监听器不会自动移除。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
这会导致内存泄漏,尤其在频繁创建/销毁通信通道的场景(如动态加载模块)。更隐蔽的问题是,关闭后又误调 port.postMessage(),控制台只报错不提示具体哪条 port 出了问题。
- 推荐封装一个
destroyPort(port)工具函数,内部先port.removeEventListener('message', handler),再port.close() - 不要依赖 GC 自动回收 port,
port引用未清空时,整个关联对象图都可能驻留内存 - 使用
port.onmessage = null可清除旧回调,但无法解绑addEventListener添加的监听器
transfer 选项传 port 到 Worker 时,原主线程 port 立即失效
向 Worker 发送消息并传入 port 时,必须把 port 放进 transfer 数组:worker.postMessage(data, [port])。此时主线程的 port 实例会立刻变为 closed,不能再调用任何方法。
新手常犯错误:在 postMessage() 后继续写 port.postMessage() 或 port.start(),结果抛出 InvalidStateError: Failed to execute 'postMessage' on 'MessagePort': port is closed。
- transfer 是所有权移交,不是复制;Worker 接收后通过
event.ports[0]获得唯一可用 port - 主线程若还需通信,应提前在 transfer 前完成初始化(如绑定监听、调用 start)
- 多个 port 需同时 transfer?确保数组里每个 port 都只出现一次,重复会导致
DOMException: Duplicate transferable
实际用起来最麻烦的从来不是 API 写法,而是端口生命周期和所有权归属——谁 close、谁 start、谁 transfer,三者顺序错一环,消息就停摆。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










