postMessage消息是否会丢失?主线程阻塞时的接收保障问询
postMessage消息投递的规范保障与浏览器行为分析
规范层面的明确保障
HTML标准对postMessage()的消息投递有严格要求:调用该方法后,用户代理必须将消息封装为MessageEvent并加入目标窗口的宏任务队列,而非直接丢弃。只要目标窗口未被销毁(比如未被移除、未关闭),这些消息会一直处于队列中,等待目标主线程处理完当前执行栈的任务后,按顺序触发message事件。
简言之,规范层面完全保障消息不会因接收方主线程阻塞而丢失,最终一定会被处理。
浏览器实际行为验证
你给出的测试代码在Chrome中验证了这一规范要求:当子帧被5秒的同步循环阻塞主线程时,主帧每秒发送的消息会被Chrome缓存到子帧的任务队列中,待阻塞结束后,子帧会一次性处理所有积压的消息,无任何丢失。
注:Firefox将沙箱化iframe与主帧置于同一线程,这属于浏览器实现细节,并未违反规范——规范仅要求消息入队,未强制跨线程隔离。
特殊例外:调试器暂停导致消息丢失
当调试器在接收方帧暂停时,此期间发送的所有消息会被丢弃,恢复调试后无法接收。这是浏览器调试模式下的特殊处理,并非规范要求,目的是避免调试期间消息队列过度积压或导致状态不一致。
测试代码示例
let iframe = document.createElement("iframe"); iframe.sandbox = "allow-scripts"; iframe.srcdoc = ` <script> window.addEventListener('message', (event) => { console.log('Child received:', event.data); }); setInterval(() => { console.log('Child: Starting heavy processing'); const startTime = Date.now(); while (Date.now() - startTime < 5000) { // Heavy loop for 5 seconds } console.log('Child: Finished heavy processing'); }, 10000); <\/script> `; document.body.append(iframe); // Send a message every second let messageIndex = 0; setInterval(() => { const message = `Message ${messageIndex}`; console.log('Parent sending:', message); iframe.contentWindow.postMessage(message, '*'); messageIndex++; }, 1000);
内容的提问来源于stack exchange,提问作者joe
相关产品推荐
相关产品推荐

