加载第三方 JavaScript

Addy Osmani
Addy Osmani
Arthur Evans

如果您优化了代码,但网站的加载速度仍然过慢,则可能是第三方脚本导致的。

第三方脚本提供了各种实用功能,可让网站变得更加动态、互动性更强且互联性更高。其中一些甚至可能对您网站的功能或收入来源至关重要。但使用这些工具存在风险

  • 它们可能会降低您网站的性能
  • 这可能会导致隐私权安全问题。
  • 它们可能不可预测,并且其行为可能会产生意想不到的后果

理想情况下,您应确保第三方脚本不会影响您网站的关键渲染路径。在本指南中,我们将详细介绍如何查找和修复与加载第三方 JavaScript 相关的问题,并最大限度地降低对用户的风险。

什么是第三方脚本?

“第三方 JavaScript”通常是指可直接从第三方供应商嵌入到任何网站中的脚本。例如:

  • 社交分享按钮(Facebook、X、LinkedIn、Mastodon)

  • 视频播放器嵌入 (YouTube、Vimeo)

  • 广告 iframe

  • 分析和指标脚本

  • 实验的 A/B 测试脚本

  • 辅助库,例如日期格式设置、动画或函数库

YouTube 视频嵌入示例
一个 YouTube 视频嵌入示例,您可以使用以下代码将其添加到网页中。
<iframe
  width="560"
  height="315"
  src="https://www.youtube.com/embed/mo8thg5XGV0"
  frameborder="0"
  allow="autoplay; encrypted-media"
  allowfullscreen
>
</iframe>

遗憾的是,嵌入第三方脚本意味着我们通常需要它们快速运行,而不是拖慢网页的速度。第三方脚本是导致网站所有者无法控制的资源导致性能缓慢的常见原因,包括以下问题:

  • 向多个服务器发出过多网络请求。网站需要发出的请求越多,加载所需的时间就越长。

  • 发送过多的 JavaScript,导致主线程繁忙。JavaScript 过多可能会阻塞 DOM 构建,从而延迟网页渲染。CPU 密集型脚本解析和执行可能会延迟用户互动并导致电池耗电。

  • 发送未优化的大型图片文件或视频可能会消耗数据流量并给用户带来费用。

  • 如果您的网页在不加小心的情况下加载脚本,可能会出现的安全问题,这些问题可能会成为单点故障 (SPOF)

  • HTTP 缓存不足,迫使浏览器发送更多网络请求来提取资源。

  • 服务器压缩不充分会导致资源加载缓慢。

  • 在内容处理完成之前,阻止内容显示。这同样适用于异步 A/B 测试脚本。

  • 使用已知会损害用户体验的旧版 API,例如 document.write()

  • DOM 元素过多或 CSS 选择器过于复杂。

  • 包含多个第三方嵌入可能会导致多次提取多个框架和库,从而浪费资源并加剧现有性能问题。

  • 第三方脚本通常使用嵌入技术,如果其服务器响应缓慢,这些技术可能会阻塞 window.onload,即使嵌入使用的是异步或延迟也是如此。

您是否能够解决第三方脚本问题,可能取决于您的网站以及您是否能够配置第三方代码的加载方式。幸运的是,有许多解决方案和工具可用于发现和解决第三方资源问题。

如何识别网页上的第三方脚本?

确定您网站上的第三方脚本并评估其对性能的影响,是优化这些脚本的第一步。我们建议您使用免费的网页速度测试工具(包括 Chrome 开发者工具PageSpeed InsightsWebPageTest)来找出耗费资源较多的脚本。这些工具会显示丰富的诊断信息,可让您了解您的网站使用了多少第三方脚本,以及哪些脚本的执行时间最长。

WebPageTest 的瀑布流视图可以突出显示大量使用第三方脚本的影响。标记泛滥一文中的以下图片显示了加载网站的主要内容(而非跟踪和营销脚本)所需的网络请求示例图。

网页测试中的广告瀑布流视图,显示实际网站与加载跟踪脚本所花时间的对比情况
此页面上的脚本加载时间比页面本身更长。

WebPageTest 的网域细分功能还可以直观地显示有多少内容来自第三方来源。它会按字节总数和请求数量对此进行细分:

按网域细分的初次观看内容数据。
显示每个第三方的请求数和字节数所占的百分比
“网域细分”图表会显示网页内容中有多少来自第三方。

如何衡量第三方脚本对网页的影响?

如果您发现某个脚本导致问题,请了解该脚本的用途,并确定您的网站是否需要该脚本才能正常运行。如有必要,请运行 A/B 测试,以平衡其感知价值与对关键用户互动度或效果指标的影响。

Lighthouse 启动时间审核

Lighthouse 的 JavaScript 启动时间审核会突出显示脚本解析、编译或评估时间较长的脚本。这有助于您识别 CPU 密集型第三方脚本。

Lighthouse 显示支持脚本评估和解析
启动时间审核会显示哪些脚本的加载时间最长。

Lighthouse 网络载荷审核

Lighthouse 网络载荷审核会识别网络请求,包括会导致网页加载时间延长并使用户的移动流量消耗超出预期的第三方网络请求。

Lighthouse 显示支持大型网络载荷
“网络载荷审核”摘要卡会显示哪些网络请求耗时最长、提取的数据量最多。

Chrome DevTools 网络请求屏蔽

借助 Chrome DevTools,您可以查看在指定脚本、样式表或其他资源不可用时网页的行为方式。这可以通过网络请求屏蔽功能来实现,该功能有助于衡量从网页中移除个别第三方资源的影响。

如需启用请求屏蔽功能,请右键点击“Network”面板中的任意请求,然后选择 Block Request 网址。然后,DevTools 抽屉中会显示“请求屏蔽”标签页,以便您管理已屏蔽的请求。

通过 DevTools 网络面板屏蔽请求网址
屏蔽单个网络请求,看看在没有这些请求的情况下网页的行为方式。

Chrome DevTools 性能面板

Chrome DevTools 中的“性能”面板可帮助您发现网页的 Web 性能问题。

  1. 点击录制
  2. 加载您的网页。开发者工具会显示一个瀑布图,表示您的网站在加载过程中所花费的时间。
  3. 前往“效果”面板底部的自下而上
  4. 点击按产品分组,然后按加载时间对网页的第三方脚本进行排序。
开发者工具“性能”面板,显示按(第三方)产品分组的“自下而上”视图
第三方脚本,按产品排序,从加载时间最长开始。

如需详细了解如何使用 Chrome DevTools 分析网页加载性能,请参阅分析运行时性能入门

以下是我们建议的用于衡量第三方脚本影响的工作流程:

  1. 使用 Network 面板衡量网页加载所需的时间。
    • 为了模拟真实情况,我们建议您开启网络节流CPU 节流。您的用户不太可能拥有快速的网络连接和桌面硬件,这些因素有助于在实验室条件下减少高开销脚本的影响。
  2. 屏蔽您认为存在问题的第三方脚本所对应的网址或网域(如需有关识别耗费大量资源的脚本的指导,请参阅 Chrome DevTools 性能面板)。
  3. 重新加载页面,然后再次测量加载时间。
    • 为了获得更准确的数据,您可能需要至少测量三次加载时间。这说明某些第三方脚本会在每次网页加载时提取不同的资源。为此,DevTools 性能面板支持多项录制。

使用 WebPageTest 衡量第三方脚本的影响

WebPageTest 支持在高级设置 > 屏蔽中阻止个别请求加载,以衡量其影响。您可以使用此功能指定要屏蔽的网域列表,例如广告网域。

WebPageTest 高级设置 < 屏蔽。
显示一个文本区域,用于指定要屏蔽的网域。
在此面板中列出要屏蔽的网域。

我们建议您按照以下工作流程使用此功能:

  1. 在不屏蔽第三方的情况下测试网页。
  2. 重复测试,并屏蔽部分第三方。
  3. 测试历史记录中选择这两项结果。
  4. 点击比较
WebPageTest 显示了比较选项,可让您比较两个报告
选择要比较的负载测试结果。

下图显示了 WebPageTest 的影片片段功能,比较了包含和不包含有效第三方资源的网页的加载顺序。我们建议您在测试各个第三方来源时查看此选项,以确定哪些网域对网页的性能影响最大。

WebPageTest 影片片段:显示在停用和启用第三方的情况下加载网站的影响
屏蔽第三方资源的影响,摘自 Andy Davies 撰写的《Using WebPageTest To Measure The Impact Of Third-Party Tags》

WebPageTest 还支持在 DNS 级别运行的两个用于屏蔽网域的命令:

WebPageTest 还提供了“单点故障 (SPOF)”标签页,可让您模拟超时或完全无法加载资源。与域名屏蔽不同,SPOF 会缓慢超时,这对于测试第三方服务在高负载或暂时不可用时网页的行为非常有用。

WebPageTest 高级设置 > SPOF > 失败的主机
使用 SPOF 测试功能模拟指定网域的故障。

使用长任务检测开销大的 iframe

当第三方 iframe 中的脚本运行时间过长时,它们可能会阻塞主线程并延迟其他任务。这些长任务可能会导致事件处理脚本运行缓慢或帧丢失,从而降低用户体验。

如需为真实用户监控 (RUM) 检测耗时较长的任务,请使用 JavaScript PerformanceObserver API 来观察 longtask 条目。这些条目包含一个提供方属性,您可以使用该属性来确定导致出现耗时较长任务的帧上下文。

以下代码会将 longtask 条目记录到控制台,其中包括一个“开销较大”的 iframe 条目:

<script>
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Attribution entry including "containerSrc":"https://example.com"
      console.log(JSON.stringify(entry.attribution));
    }
  });

  observer.observe({entryTypes: ['longtask']});
</script>

<!-- Imagine this is an iframe with expensive long tasks -->
<iframe src="https://example.com"></iframe>

如需详细了解如何监控长任务,请参阅以用户为中心的性能指标

如何高效加载第三方脚本?

如果第三方脚本导致网页加载速度变慢,您可以通过以下几种方式提高性能:

  • 使用 asyncdefer 属性加载脚本,以免阻止文档解析。
  • 如果第三方服务器运行缓慢,请考虑自行托管脚本。
  • 如果该脚本无法为您的网站带来明确价值,请将其移除。
  • 使用 <link rel=preconnect><link rel=dns-prefetch>资源提示对托管第三方脚本的网域执行 DNS 查找。

使用 asyncdefer

JavaScript 执行会阻止解析器。当浏览器遇到脚本时,必须暂停 DOM 构建,将脚本传递给 JavaScript 引擎,并允许脚本执行完毕,然后再继续构建 DOM。

asyncdefer 属性会更改此行为,如下所示:

  • async 会导致浏览器在继续解析 HTML 文档的同时异步下载脚本。脚本下载完毕后,在脚本执行期间,解析会被阻止。

  • defer 会导致浏览器在继续解析 HTML 文档时异步下载脚本,然后等待运行脚本,直到文档解析完成。

请始终为第三方脚本使用 asyncdefer,除非该脚本对关键渲染路径至关重要。如果脚本需要在加载过程中尽早运行(例如某些分析脚本),请使用 async。对重要性较低的资源(例如在网页上渲染的位置低于用户最初看到的位置的视频)使用 defer

如果性能是您的首要考虑因素,我们建议您等到网页的关键内容加载完毕后再添加异步脚本。我们不建议对 jQuery 等基本库使用 async

某些脚本必须在不使用 asyncdefer 的情况下加载,尤其是对您的网站至关重要的脚本。其中包括您的网站无法正常运行时所需的界面库或内容分发网络 (CDN) 框架。

其他脚本如果以异步方式加载,则无法正常运行。请查看您使用的所有脚本的文档,并将无法异步加载的所有脚本替换为可以异步加载的替代脚本。请注意,某些第三方建议同步运行其脚本,即使这些脚本在异步运行时也能正常运行。

请注意,async 并不能解决所有问题。如果您的网页包含大量脚本(例如用于广告用途的跟踪脚本),异步加载这些脚本并不能防止它们减慢网页加载速度。

使用资源提示缩短连接设置时间

与第三方来源建立连接可能需要很长时间,尤其是在网络速度较慢的情况下,因为网络请求包含多个复杂的组件,包括 DNS 查询和重定向。您可以使用 资源提示在网页加载流程的早期对托管第三方脚本的网域执行 DNS 查找,以便稍后更快地处理网络请求的其余部分:

<link rel="dns-prefetch" href="http://example.com" />

如果您要连接到的第三方网域使用 HTTPS,您还可以使用 ,它既会执行 DNS 查询,还会解析 TCP 往返并处理 TLS 协商。这些其他步骤可能非常缓慢,因为它们涉及验证 SSL 证书,因此预连接可以大大缩短加载时间。

<link rel="preconnect" href="https://cdn.example.com" />

包含 iframe 的“沙盒”脚本

如果您直接将第三方脚本加载到 iframe 中,它不会阻止主页面的执行。AMP 使用此方法将 JavaScript 从关键路径中排除。请注意,此方法仍会阻止 onload 事件,因此请尽量不要将重要功能附加到 onload

Chrome 还支持权限政策(以前称为功能政策),这组政策允许开发者选择性地禁止访问某些浏览器功能。您可以使用此功能来防止第三方内容向网站引入不必要的行为。

自行托管第三方脚本

如果您想更好地控制关键脚本的加载方式(例如缩短 DNS 时间或改进 HTTP 缓存标头),则可以自行托管该脚本。

不过,自行托管也存在自身的问题,尤其是在更新脚本时。在您手动更新脚本之前,自托管脚本不会自动更新 API 更改或安全修复程序,这可能会导致收入损失或安全问题。

或者,您也可以使用服务工件缓存第三方脚本,以便更好地控制从网络提取脚本的频率。您还可以使用服务工创建加载策略,以节流非必需的第三方请求,直到您的网页达到关键用户时刻。

对较小用户样本进行 A/B 测试

A/B 测试(或分组测试)是一种实验方法,用于对网页的两个版本进行实验,以分析用户体验和行为。它会向网站流量的不同样本提供页面版本,并根据分析数据确定哪个版本的转化率更高。

不过,A/B 测试会延迟渲染,以便确定需要启用哪项实验。JavaScript 通常用于检查您的任何用户是否属于 A/B 测试实验,然后启用正确的变体。即使未参与实验的用户,也会因此流程而体验变差。

为了加快网页呈现速度,我们建议您将 A/B 测试脚本发送给用户群中较小的一部分样本,并运行用于确定要显示哪个网页版本的服务器端代码。

延迟加载第三方资源

如果嵌入的第三方资源(例如广告和视频)构建不当,可能会是导致网页速度缓慢的主要原因。只有在必要时,才能使用延迟加载来加载嵌入的资源,例如,等到用户滚动到足够低的位置才能在页脚中投放广告。您还可以在主要网页内容加载后,但在用户可能与网页互动之前,延迟加载第三方内容。

一张插图,显示对上方可见区域体验至关重要的资源,以及重要性较低且可以延迟加载的资源。
您可以延迟加载用户在网页加载时不会立即看到的资源。

延迟加载资源时请务必小心,因为这通常涉及 JavaScript 代码,而 JavaScript 代码可能会受到不稳定的网络连接的影响。

DoubleClick 在其官方文档中提供了有关如何延迟加载广告的指南。

使用 Intersection Observer 高效实现延迟加载

长期以来,用于检测元素是否在视口中可见以实现延迟加载的方法容易出错,并且通常会降低浏览器速度。这些效率低下的方法通常会监听滚动调整大小事件,然后使用 getBoundingClientRect() 等 DOM API 计算元素相对于视口的位置。

IntersectionObserver 是一个浏览器 API,可让网页所有者高效检测被观察元素何时进入或离开浏览器的视口。LazySizes 还可选支持 IntersectionObserver。

延迟加载分析

如果您推迟加载 Google Analytics 脚本的时间过长,可能会错过有价值的 Google Analytics 数据。幸运的是,有可用策略可用于延迟初始化 Google Analytics,同时保留早期网页加载数据。

Phil Walton 的博文《The Google Analytics Setup I Use on Every Site I Build》(我为自己构建的每个网站使用的 Google Analytics [分析] 设置)介绍了 Google Analytics 的一项此类策略。

安全地加载第三方脚本

本部分提供了有关如何尽可能安全地加载第三方脚本的指导。

避免使用 document.write()

第三方脚本(尤其是旧版服务的脚本)有时会使用 document.write() 注入和加载脚本。这会带来问题,因为 document.write() 的行为不一致,其失败情况难以调试。

如需解决 document.write() 问题,请勿使用它。在 Chrome 53 及更高版本中,如果 document.write() 的使用存在问题,Chrome 开发者工具会向控制台记录警告:

突出显示使用 document.write() 的第三方嵌入内容违规情况的 DevTools 控制台警告
Chrome 开发者工具会标记 document.write() 用法。

如果您收到此错误,可以查找发送到浏览器的 HTTP 标头,以检查您的网站是否存在 document.write() 用量问题。Lighthouse 还可以突出显示仍在使用 document.write() 的任何第三方脚本。

Lighthouse 最佳实践审核标记了 document.write() 的使用
Lighthouse 报告,显示哪些脚本使用了 document.write()

谨慎使用跟踪代码管理器

代码是一种代码段,可让数字营销团队收集数据、设置 Cookie 或将社交媒体 widget 等第三方内容集成到网站中。这些代码会向您的网页添加网络请求、JavaScript 依赖项和其他资源,这些资源可能会影响网页的性能,而且随着添加的代码越来越多,要尽可能减少对用户的影响就越难。

为了确保网页快速加载,我们建议您使用代码管理器,例如 Google 跟踪代码管理器 (GTM)。借助 GTM,您可以异步部署代码,以免代码相互阻塞加载,从而减少浏览器执行代码所需的网络调用次数,并在其数据层界面中收集代码数据。

使用跟踪代码管理器的风险

虽然跟踪代码管理器旨在简化网页加载,但如果使用不当,可能会通过以下方式导致网页加载速度变慢:

  • 如果代码管理器中的代码和自动事件监听器过多,会导致浏览器发出的网络请求数量超出必要,并降低代码快速响应事件的能力。
  • 具有凭据和访问权限的任何人都可以向您的跟踪代码管理器添加 JavaScript。这不仅会增加加载网页所需的昂贵网络请求数量,还可能会因不必要的脚本而导致安全风险和其他性能问题。为降低这些风险,我们建议您限制对代码管理器的访问权限。

避免使用会污染全局作用域的脚本

第三方脚本可能会以各种方式导致您的网页意外中断:

  • 加载 JavaScript 依赖项的脚本可能会使用与您的代码互动不良的代码污染全局作用域。
  • 意外更新可能会导致破坏性更改。
  • 第三方代码可能会在传输过程中被修改,因此在测试和部署网页时会表现出不同的行为。

我们建议您定期审核您加载的第三方脚本,以检查是否存在恶意行为者。您还可以实现自测、子资源完整性以及第三方代码的安全传输,以确保网页安全无虞。

缓解策略

以下是一些大规模策略,可最大限度地减少第三方脚本对您网站的性能和安全性的影响:

  • HTTPS:使用 HTTPS 的网站不得依赖于使用 HTTP 的第三方。如需了解详情,请参阅混合内容

  • 沙盒:考虑在具有 sandbox 属性的 iframe 中运行第三方脚本,以限制脚本可执行的操作。

  • 内容安全政策 (CSP):您可以使用服务器响应中的 HTTP 标头为您的网站定义可信脚本行为,并检测和减少某些攻击(例如跨站脚本攻击 [XSS])的影响。

以下示例展示了如何使用 CSP 的 script-src 指令指定网页允许的 JavaScript 来源:

// Given this CSP header Content-Security-Policy: script-src
https://example.com/ // The following third-party script will not be loaded or
executed

<script src="https://not-example.com/js/library.js"></script>

深入阅读

如需详细了解如何优化第三方 JavaScript,我们建议您阅读以下内容:

感谢 Kenji Baheux、Jeremy Wagner、Pat Meenan、Philip Walton、Jeff Posnick 和 Cheney Tsai 的审核。