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

Firefox ESR 91 Web Worker中requestAnimationFrame未定义如何解决

问题成因

requestAnimationFrame最初是仅暴露在主线程window上下文的API,Web Worker的独立全局作用域DedicatedWorkerGlobalScope早期并未默认提供该接口。
你使用的v91.10.0esr是火狐2022年发布的旧长期支持版本,该版本并未实装Worker上下文下的requestAnimationFrame支持——火狐从v113正式版开始才在Dedicated Worker全局作用域中暴露该API。安卓版Firefox、Edge、Chrome因为常规版本迭代速度快,更早实装了这一特性,因此同一段代码在这些环境中可以正常运行,在旧版Firefox ESR中会直接抛出引用不存在的错误。

解决方案
  • 方案1:升级浏览器版本。如果业务场景允许终端用户升级浏览器,直接将Firefox升级至v113及以上版本,即可原生支持Worker内直接调用requestAnimationFrame,无需修改现有业务代码。
  • 方案2:添加兼容polyfill。如果需要覆盖旧版Firefox ESR等不支持Worker内requestAnimationFrame的环境,可以通过主线程和Worker的消息通信实现兼容层,参考实现如下:
    把Worker侧的兼容逻辑和业务代码拼接后传入Blob,主线程添加对应的消息转发逻辑,完整可运行代码如下:
    // 拼接polyfill和原有Worker业务代码
    const workerCode = `
    // Worker内rAF兼容polyfill,需放在业务代码最前
    if (typeof requestAnimationFrame === 'undefined') {
      const rafCallbacks = new Map();
      let rafId = 0;
    
      self.addEventListener('message', (e) => {
        if (e.data?.type === '__raf_trigger__') {
          const callback = rafCallbacks.get(e.data.id);
          if (callback) {
            callback(e.data.timestamp);
            rafCallbacks.delete(e.data.id);
          }
        }
      });
    
      self.requestAnimationFrame = (callback) => {
        const currentId = rafId++;
        rafCallbacks.set(currentId, callback);
        self.postMessage({
          type: '__raf_request__',
          id: currentId
        });
        return currentId;
      };
    
      self.cancelAnimationFrame = (id) => {
        rafCallbacks.delete(id);
        self.postMessage({
          type: '__raf_cancel__',
          id
        });
      };
    }
    
    // 原有Worker业务代码
    requestAnimationFrame(() => self.postMessage('requestAnimationFrame in web-worker process'));
    `;
    
    const worker = new Worker(
      URL.createObjectURL(
        new Blob([workerCode], { type: "text/javascript" })
      )
    );
    
    // 主线程rAF转发逻辑
    const mainRafIdMap = new Map();
    worker.addEventListener("message", e => {
      // 拦截rAF相关内部消息
      if (e.data?.type === '__raf_request__') {
        const mainRafId = requestAnimationFrame((timestamp) => {
          mainRafIdMap.delete(e.data.id);
          worker.postMessage({
            type: '__raf_trigger__',
            id: e.data.id,
            timestamp
          });
        });
        mainRafIdMap.set(e.data.id, mainRafId);
        return;
      }
      if (e.data?.type === '__raf_cancel__') {
        const targetRafId = mainRafIdMap.get(e.data.id);
        if (targetRafId) {
          cancelAnimationFrame(targetRafId);
          mainRafIdMap.delete(e.data.id);
        }
        return;
      }
    
      // 原有业务消息处理逻辑
      console.log(e.data);
    });
    
    requestAnimationFrame(() => console.log("requestAnimationFrame in main process"));
    
    该polyfill的回调触发时机、时间戳参数均和原生规范对齐,可覆盖绝大多数业务使用场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:57:27