You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中使用postMessage与新开弹窗通信出现竞态条件如何解决?

解决方案

核心逻辑修正

将原有的「父窗口主动发INIT触发弹窗响应」的逻辑反转,由弹窗完成资源加载、事件监听注册完成后,主动向父窗口(window.opener)发送就绪信号,父窗口收到信号后再发送业务消息,从根源消除竞态条件。父窗口的message监听会在弹窗加载完成前完成注册,因此弹窗主动发送的READY信号100%能被父窗口捕获,不存在消息丢失的情况。

修正后代码

父窗口代码

删除不可靠的setTimeout逻辑,保留origin安全校验,同时补全原代码的语法错误:

const windowFeatures  = "height=800,width=1280,toolbar=1,menubar=1,location=1"; 
const printWindow = window.open("/print", "Print_Me", windowFeatures);

// 兜底判断:弹窗被浏览器拦截时的处理
if (!printWindow) {
  alert("弹窗被浏览器拦截,请调整权限后重试");
}

window.addEventListener("message", (event) => { 
  if(event.origin !== window.origin)  return;  
  if(event.data.printPageStatus === "READY") {
    printWindow.postMessage({message: "from parent"}, window.origin);
    return;
  }
});

弹窗代码

删除等待INIT的逻辑,页面/组件就绪后直接向父窗口发READY信号:

constructor() {
  window.addEventListener("message", event => {
    if(event.origin !== window.origin)  return;    
    if(event.data.message === "from parent") {
      this.processMessages(event.data);
    }
  }, false);
}

// 选择对应技术栈的就绪触发时机即可:
// 原生JS:绑定到 window.onload / DOMContentLoaded 事件
// Vue:写在 mounted 钩子中
// React:写在空依赖的 useEffect 中
onReady() {
  window.opener.postMessage({printPageStatus: "READY"}, window.origin);
}

额外优化建议

  • 增加超时兜底:父窗口打开弹窗后启动定时器,若10s内未收到READY信号,判定为弹窗加载失败,关闭弹窗并提示用户
  • 消息唯一标识:若同时打开多个弹窗,可在打开时生成唯一ID传递给弹窗,弹窗回传READY时携带ID,避免多个弹窗的消息混淆
  • 销毁清理:父窗口在收到业务处理完成通知后,移除对应的message监听,避免内存泄漏

内容的提问来源于stack exchange,提问作者Zeo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:54:04