加载第三方 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 选择器过多。

  • 包含多个第三方嵌入可能会导致多个框架和库被多次拉取,从而浪费资源并使现有的性能问题变得更糟。

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

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

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

识别您网站上的第三方脚本并确定其性能影响是优化这些脚本的第一步。我们建议您使用免费的 Web 速度测试工具(包括 Chrome 开发者工具PageSpeed InsightsWebPageTest)来识别开销高昂的脚本。这些工具会显示丰富的诊断信息,让您知道自己的网站使用了多少第三方脚本以及哪些脚本执行时间最长。

WebPageTest 的瀑布视图可以突出显示大量使用第三方脚本的影响。来自 Tags Gone Wild 的下图显示了加载网站主要内容(而非跟踪和营销脚本)所需的网络请求示例图表。

pagetest 中的瀑布图(其中显示了实际网站)与加载跟踪脚本所花费的时间
此页面上的脚本比页面本身的加载时间要长。

WebPageTest 的网域细分功能也有助于直观呈现有多少来自第三方的内容。它会按总字节数和请求数细分:

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

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

当您看到导致问题的脚本时,请确认该脚本的作用,并确定您的网站是否需要其正常运行。如有必要,可以运行 A/B 测试,以平衡该测试的感知价值与对关键用户互动度或效果指标的影响。

Lighthouse 启动时间审核

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

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

Lighthouse 网络载荷审核

Lighthouse 网络载荷审核可识别网络请求,包括会拖慢页面加载时间并导致用户在移动数据上所花的时间超过预期的第三方网络请求。

显示支持大型网络载荷的 Lighthouse
网络载荷审核会显示哪些网络请求用时最多,提取的数据最多。

Chrome DevTools 网络请求屏蔽

借助 Chrome 开发者工具,您可以查看指定脚本、样式表或其他资源不可用时页面的行为。这是通过网络请求屏蔽功能实现的,该功能可帮助衡量从网页中移除各个第三方资源的影响。

如需启用请求屏蔽功能,请右键点击“网络”面板中的任意请求,然后选择屏蔽请求网址。随后,开发者工具抽屉式导航栏中会显示一个请求屏蔽标签页,让您管理哪些请求已被屏蔽。

通过开发者工具网络面板屏蔽请求网址
屏蔽个别网络请求,了解在没有网络请求的情况下网页的行为。

Chrome 开发者工具性能面板

Chrome 开发者工具中的“性能”面板有助于识别网页性能方面的问题。

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

如需详细了解如何使用 Chrome 开发者工具分析网页加载性能,请参阅开始分析运行时性能

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

  1. 使用“Network”面板可以衡量加载网页所需的时间。
    • 如需模拟实际情况,我们建议您开启网络节流CPU 节流。您的用户不太可能使用快速的网络连接和桌面硬件来降低昂贵的脚本在实验室条件下的影响。
  2. 屏蔽对您认为有问题的第三方脚本负责的网址或网域(如需了解如何识别成本高昂的脚本,请参阅 Chrome 开发者工具性能面板)。
  3. 请重新加载网页,并再次测量加载时间。
    • 为了获得更准确的数据,您可能需要至少测量三个加载时间。这就说明了有些第三方脚本会在每次网页加载时提取不同资源。为了帮助解决此问题,开发者工具性能面板支持多个记录。

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

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

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

如需使用此功能,我们建议您采用以下工作流程:

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

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

WebPageTest 幻灯影片展示在使用/停用第三方时加载网站的影响
《使用 WebPageTest 衡量第三方代码的影响》一文中屏蔽第三方资源的影响,作者:Andy Davies。

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

如果您主要关注性能,建议您等到网页的关键内容加载完毕后再添加异步脚本。我们不建议将 async 用于基本的库(例如 jQuery)。

某些脚本必须在不加载 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 更改或安全修复程序的自动更新,这可能会导致收入损失或安全问题,直到您手动更新脚本为止。

作为替代方案,您可以使用 Service Worker 缓存第三方脚本,以便更好地控制从网络提取脚本的频率。您还可以使用 Service Worker 创建加载策略,在网页进入关键用户时刻之前限制非必要的第三方请求。

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

A/B 测试(或拆分测试)是一种针对网页的两个版本进行实验以分析用户体验和行为的技术。它会将网页版本提供给不同的网站流量样本,并通过分析确定哪个版本的转化率更高。

不过,根据设计,A/B 测试会延迟渲染,以确定需要启动的实验。JavaScript 通常用于检查用户是否属于某个 A/B 测试实验,然后启用正确的变体。即使对于没有参与实验的用户,此过程也可能会使体验变差。

为了加快网页呈现速度,我们建议您向规模较小的用户群样本发送 A/B 测试脚本,并运行代码来决定在服务器端显示哪个版本的网页。

延迟加载第三方资源

如果构建不善,嵌入式第三方资源(例如广告和视频)可能是导致网页速度变慢的主要原因。延迟加载可用于仅在必要时加载嵌入式资源,例如,等到用户滚动足够长的距离才能看到它们时,才在页脚中投放广告。此外,您还可以在主页面内容加载之后、用户可能以其他方式与页面互动之前延迟加载第三方内容。

一张插图,展示了对首屏体验至关重要的资源以及不太重要且可延迟加载的资源。
您可以延迟加载用户在网页加载时不会立即看到的资源。

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

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

利用 Intersection Observer 进行高效延迟加载

过去,出于延迟加载目的检测某个元素在视口中是否可见的方法容易出错,并且往往会降低浏览器的运行速度。这些低效方法通常会监听 scrollresize 事件,然后使用 getBoundingClientRect() 等 DOM API 计算元素相对于视口的位置。

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

延迟加载分析

如果您延迟加载分析脚本的时间过长,可能会错失宝贵的分析数据。幸运的是,有一些策略可用于延迟初始化分析,同时保留早期的网页加载数据。

Phil Walton 的博文我在构建的每个网站上使用的 Google Analytics(分析)设置介绍了这样一种 Google Analytics(分析)策略。

安全加载第三方脚本

本部分介绍了如何尽可能安全地加载第三方脚本。

避免使用 document.write()

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

document.write() 问题的解决方法就是不使用该功能。在 Chrome 53 及更高版本中,如果 document.write() 使用出现问题,Chrome 开发者工具会将警告记录到控制台:

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

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

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

谨慎使用跟踪代码管理器

“代码”是一种代码段,可让数字营销团队收集数据、设置 Cookie 或将第三方内容(如社交媒体微件)集成到网站中。这些代码会向您的网页添加网络请求、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 做出的评价。