#27625·emscripten

BUILD_AS_WORKER: 在 MODULARIZE 下, onmessage 会安装得太晚,甚至会在主线程上安装

作者: tovabar创建于 2026年8月30日更新于 2026年8月31日
  1. 处理器即使模块未在工作线程中运行也会被安装 IIFE 在加载模块的任何环境中运行,并无条件地安装 onmessage。因此,带有 -sBUILD_AS_WORKER 并同时在主线程中运行的模块会覆盖 window.onmessage,从而接管整个页面的消息传递。这不是一个无声的接管。页面从其他来源接收的任何消息现在都会到达此处理器,该处理器会中止:
javascript
var func = Module['_' + msg.data['funcName']];
if (!func) abort('invalid worker function to call: ' + msg.data['funcName']);

或者直接抛出 TypeError,如果 msg.data 不是具有 funcName 的对象(例如,来自嵌入页面或其他库的普通 postMessage('...'))。

在 IIFE 的顶部添加一个保护措施似乎是正确的解决方案:

javascript
if (!ENVIRONMENT_IS_WORKER) return;
  1. 在 MODULARIZE 下,在工厂运行之前收到的消息会被丢弃 带有 -sMODULARIZE 的 IIFE 位于模块工厂中,应用程序在准备好时会调用它。然而,工作线程在创建时就开始接收消息了 — 因此在 "工作脚本开始执行" 和 "工厂被调用" 之间存在一个窗口,在这段时间内收到这些消息。 现有的缓冲不会覆盖这个窗口。messageBuffer 只从 IIFE 安装的处理器内开始收集消息,因此它保护了工厂运行和 runtimeInitialized 之间的时间间隔 — 而不是更早的时间间隔。 自然的解决方案是在工作线程引导中安装一个小型缓冲 onmessage,直到工厂被调用为止。这也不起作用:此 IIFE 覆盖了 onmessage,并从 messageBuffer = null 开始,因此之前处理器收集的所有内容都被丢弃。 最终结果是,带有 MODULARIZE 的 BUILD_AS_WORKER 模块在应用程序实例化它之前默默丢弃了任何发送的消息 — 无法弥补这个差距。 我们本地提供的解决方案是 IIFE 采用现有的缓冲,如果存在的话:
javascript
var messageBuffer = typeof workerMessageBuffer != 'undefined' ? workerMessageBuffer : null, buffer = 0;
// Upstream 只从其自身处理器内开始启动重发器,

内容来源: emscripten-core/emscripten