BUILD_AS_WORKER: 在 MODULARIZE 下, onmessage 会安装得太晚,甚至会在主线程上安装
作者: tovabar创建于 2026年8月30日更新于 2026年8月31日
- 处理器即使模块未在工作线程中运行也会被安装
IIFE 在加载模块的任何环境中运行,并无条件地安装
onmessage。因此,带有-sBUILD_AS_WORKER并同时在主线程中运行的模块会覆盖window.onmessage,从而接管整个页面的消息传递。这不是一个无声的接管。页面从其他来源接收的任何消息现在都会到达此处理器,该处理器会中止:
var func = Module['_' + msg.data['funcName']];
if (!func) abort('invalid worker function to call: ' + msg.data['funcName']);或者直接抛出 TypeError,如果 msg.data 不是具有 funcName 的对象(例如,来自嵌入页面或其他库的普通 postMessage('...'))。
在 IIFE 的顶部添加一个保护措施似乎是正确的解决方案:
if (!ENVIRONMENT_IS_WORKER) return;- 在 MODULARIZE 下,在工厂运行之前收到的消息会被丢弃
带有
-sMODULARIZE的 IIFE 位于模块工厂中,应用程序在准备好时会调用它。然而,工作线程在创建时就开始接收消息了 — 因此在 "工作脚本开始执行" 和 "工厂被调用" 之间存在一个窗口,在这段时间内收到这些消息。 现有的缓冲不会覆盖这个窗口。messageBuffer只从 IIFE 安装的处理器内开始收集消息,因此它保护了工厂运行和runtimeInitialized之间的时间间隔 — 而不是更早的时间间隔。 自然的解决方案是在工作线程引导中安装一个小型缓冲onmessage,直到工厂被调用为止。这也不起作用:此 IIFE 覆盖了onmessage,并从messageBuffer = null开始,因此之前处理器收集的所有内容都被丢弃。 最终结果是,带有 MODULARIZE 的BUILD_AS_WORKER模块在应用程序实例化它之前默默丢弃了任何发送的消息 — 无法弥补这个差距。 我们本地提供的解决方案是 IIFE 采用现有的缓冲,如果存在的话:
var messageBuffer = typeof workerMessageBuffer != 'undefined' ? workerMessageBuffer : null, buffer = 0;
// Upstream 只从其自身处理器内开始启动重发器,
…内容来源: emscripten-core/emscripten