你以为 iframe 里的动画和定时器只在 iframe 内部刷?Safari 28 今天把跨域 iframe 的性能账彻底算清了

你在页面上嵌了一个第三方聊天窗口、一个广告 iframe,或者一个社交分享按钮。这些 iframe 里的 JavaScript 可能正在跑动画、setInterval 轮询、requestAnimationFrame 渲染循环。以前这些和你主页面不在同一个域的 iframe,和你的主页面共享同一套时钟,iframe 里的 rAF 和定时器会直接影响主页面性能。Safari 28 今天把这个跨域性能账彻底算清楚了:未经用户交互的跨域 iframe,DOM 定时器节流到 30fps,和主页面解耦。

问题:跨域 iframe 如何拖慢你的主页面

浏览器的事件循环是全局的。requestAnimationFrame 的回调、DOM 定时器(setTimeout / setInterval)的触发时机,都在同一个渲染进程的主线程上排队。哪怕 iframe 是在完全不同域下运行的,它的 rAF 回调和定时器触发仍然会插入主线程的任务队列,和你的主页面代码抢执行时间。

这带来几种常见的性能损耗:

  • 主页面滚动卡顿:第三方 iframe 在后台跑动画或轮询,每次 rAF 回调都要在主线程上执行一次,主页面滚动帧被挤压
  • 定时器风暴:多个第三方 widget 各自定义 setInterval(..., 16)(约 60fps),在跨域 iframe 里叠加,主页面每 16ms 要处理多个定时器任务
  • 电池消耗:后台 iframe 持续以 60fps 运行渲染循环,无意义地消耗移动设备电量

修复:Safari 28 的节流机制

Safari 28 (WebKit r215116, r215070, r215153) 引入了对跨域 iframe 的性能节流规则:

  • DOM 定时器节流:setTimeout / setInterval 在用户未交互的跨域 iframe 内被节流至 30fps(每 33ms 最多触发一次)
  • rAF 回调节流:requestAnimationFrame 在同类 iframe 内的回调频率同样限制在 30fps
  • 触发条件:iframe 的域与父页面域不同(cross-origin),且用户尚未与该 iframe 进行过任何交互(未点击、未输入、未滚动)
Safari 28: WebKit r215116 (DOM timers 30fps) + r215070+r215153 (rAF 30fps)
生效条件:cross-origin iframe + 用户未交互

哪些场景受影响最大

正面影响(优化了你的页面):

  • 嵌入了第三方聊天/客服 widget(通常跑高频轮询)
  • 嵌入了广告 iframe(视频广告的 rAF 渲染循环)
  • 嵌入了社交分享按钮(某些实现里带动画效果)
  • 嵌入了第三方评论系统

这些以前「偷走」的帧时间,现在会被 Safari 自动回收。

需要注意的(可能影响功能的):

  • 实时数据更新:如果第三方 iframe 内部有股票行情、比分直播等高频数据拉取逻辑,setInterval 被节流到 30fps 会导致数据刷新变慢
  • Canvas 动画游戏:在跨域 iframe 里运行的轻量 Canvas 游戏/动画,原生 60fps 会降级到 30fps
  • 进度条/倒计时:如果 iframe 内部有精确到毫秒的倒计时逻辑,现在可能不再精确

Before / After

// === 第三方 iframe 内的代码(以前)===
setInterval(() => {
  fetch('/api/latest-data'); // 每 16ms 发一次,高频无效
  updateClock();             // 60fps 时钟刷新
}, 16);

// === Safari 28 以后 ===
// setInterval → 最多每 33ms 触发一次(30fps)
// rAF 回调 → 最多每 33ms 执行一次(30fps)
// 主页面性能得到保护

这是 Safari 独家的,还是行业趋势

目前这是 Safari(WebKit)的独立行为。Chrome 和 Firefox 尚未公布相同的节流机制。

不过,这个方向符合浏览器厂商对「第三方内容性能隔离」的长期关注。Safari 率先实现 30fps 节流,给 Web 平台提供了一个性能隔离的参考实现。

建议:如果你有依赖跨域 iframe 高频行为的场景,现在要测试 Safari 28 的影响。对于大多数应用来说,这个节流是正向优化。

如何判断 iframe 是否被节流

// 在 iframe 内部
const start = performance.now();
setTimeout(() => {
  const elapsed = performance.now() - start;
  // 被节流:约 33ms;未被节流:约 16ms
  console.log(`Actual interval: ${elapsed.toFixed(1)}ms`);
}, 16);

下一步

  • 检查你的第三方 iframe:如果你在页面里嵌入了跨域 iframe(广告、聊天、社交组件),确认这些组件在高频率更新场景下的行为是否受影响
  • 与第三方供应商沟通:如果你的 iframe 组件有实时数据需求,告知供应商在 Safari 28 下可能需要调整轮询频率
  • 这个变化对大多数网站是正向的:主页面性能会因此提升,特别是移动端低电量设备

评论区

0 条评论

登录后可评论。

阿速·性能优化 11 阅读