如果您已优化代码,但网站加载速度仍然过慢,则可能是第三方脚本的问题。
第三方脚本提供了各种实用功能,使网络更具动态性、互动性和互联性。其中一些甚至可能对您网站的功能或收入来源至关重要。但使用它们存在风险:
- 它们可能会降低网站的性能。
- 它们可能会导致隐私或安全问题。
- 它们可能无法预测,其行为可能会产生意外后果。
理想情况下,您需要确保第三方脚本不会影响网站的关键渲染路径。在本指南中,我们将逐步介绍如何查找和修复与加载第三方 JavaScript 相关的问题,并最大限度地降低用户面临的风险。
什么是第三方脚本?
第三方 JavaScript 通常是指可以直接从第三方供应商嵌入到任何网站的脚本。例如:
社交分享按钮(Facebook、X、LinkedIn、Mastodon)
视频播放器嵌入(YouTube、Vimeo)
广告 iframe
分析和指标脚本
用于实验的 A/B 测试脚本
辅助库,例如日期格式设置、动画或函数库
<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。
您能否解决第三方脚本问题可能取决于您的网站以及您配置第三方代码加载方式的能力。幸运的是,有许多解决方案和工具可用于查找和解决第三方资源的问题。
如何识别网页上的第三方脚本?
识别网站上的第三方脚本并确定其对性能的影响是优化这些脚本的第一步。我们建议您使用免费的网站测速工具(包括 Chrome 开发者工具、PageSpeed Insights 和 WebPageTest)来找出耗费资源的脚本。这些工具会显示丰富的诊断信息,可让您了解网站使用了多少个第三方脚本,以及哪些脚本执行时间最长。
WebPageTest 的瀑布视图可以突出显示大量使用第三方脚本的影响。下图来自 Tags Gone Wild,展示了加载网站主要内容(而非跟踪和营销脚本)所需的网络请求示例图。
WebPageTest 的网域细分也有助于直观了解有多少内容来自第三方来源。它会按总字节数和请求数进行细分:
如何衡量第三方脚本对网页的影响?
当您发现某个脚本导致问题时,请找出该脚本的作用,并确定您的网站是否需要该脚本才能正常运行。如有必要,请运行 A/B 测试,以平衡其感知价值与对关键用户互动度或效果指标的影响。
Lighthouse 启动时间审核
Lighthouse JavaScript 启动时间审核会突出显示脚本解析、编译或评估时间较长的脚本。 这有助于您识别 CPU 密集型第三方脚本。
Lighthouse 网络载荷审核
Lighthouse 网络载荷审核可识别网络请求,包括会延长网页加载时间并导致用户在移动流量上花费超出预期的第三方网络请求。
Chrome 开发者工具网络请求屏蔽
借助 Chrome 开发者工具,您可以查看当指定的脚本、样式表或其他资源不可用时,网页的行为。这可以通过网络请求屏蔽功能来实现,该功能有助于衡量从网页中移除单个第三方资源的影响。
如需启用请求屏蔽功能,请右键点击“网络”面板中的任意请求,然后选择屏蔽请求网址。然后,DevTools 抽屉式导航栏中会显示一个请求屏蔽标签页,您可以在其中管理已屏蔽的请求。
Chrome 开发者工具的“性能”面板
Chrome 开发者工具中的“性能”面板有助于找出网页性能问题。
- 点击录制。
- 加载您的网页。开发者工具会显示一个瀑布图,表示网站如何花费加载时间。
- 前往“Performance”面板底部的 Bottom-up。
- 点击按产品分组,然后按加载时间对网页的第三方脚本进行排序。
如需详细了解如何使用 Chrome 开发者工具分析网页加载性能,请参阅开始分析运行时性能。
以下是我们推荐的用于衡量第三方脚本影响的工作流程:
- 使用“网络”面板衡量加载网页所需的时间。
- 屏蔽您认为有问题的第三方脚本对应的网址或网域(如需了解如何识别耗费资源的脚本,请参阅 Chrome 开发者工具的“性能”面板)。
- 重新加载网页,然后再次测量加载时间。
- 为了获得更准确的数据,您可能需要至少测量三次加载时间。这说明了一些第三方脚本在每次网页加载时提取不同的资源。 为了解决这个问题,开发者工具的“性能”面板支持多次录制。
使用 WebPageTest 衡量第三方脚本的影响
WebPageTest 支持在高级设置 > 屏蔽中屏蔽单个请求的加载,以衡量其影响。使用此功能可指定要屏蔽的网域列表,例如广告网域。
我们建议您按照以下工作流程使用此功能:
- 在不屏蔽第三方的情况下测试网页。
- 在屏蔽部分第三方的情况下重复测试。
- 从测试历史记录中选择两个结果。
- 点击比较。
下图显示了 WebPageTest 的幻灯影片功能,该功能比较了包含和不包含活跃第三方资源的网页的加载顺序。我们建议您在测试单个第三方源时检查此项,以确定哪些网域对网页性能的影响最大。
WebPageTest 还支持在 DNS 级别运行的两个命令,用于屏蔽网域:
blockDomains接受要屏蔽的网域列表。- blockDomainsExcept 接受网域列表,并屏蔽列表中没有的所有内容。
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>
如需详细了解如何监控长任务,请参阅以用户为中心的效果指标。
如何高效加载第三方脚本?
如果第三方脚本导致网页加载速度变慢,您可以通过以下几种方式来提升性能:
- 使用
async或defer属性加载脚本,以免阻塞文档解析。 - 如果第三方服务器速度较慢,请考虑自行托管脚本。
- 如果脚本无法为您的网站带来明显的价值,请将其移除。
- 使用 Resource Hints(例如
<link rel=preconnect>或<link rel=dns-prefetch>)对托管第三方脚本的网域执行 DNS 查找。
使用 async 或 defer
JavaScript 执行会阻止解析器。当浏览器遇到脚本时,必须暂停 DOM 构建,将脚本传递给 JavaScript 引擎,并允许脚本执行,然后再继续构建 DOM。
async 和 defer 属性会按如下方式更改此行为:
async会使浏览器在继续解析 HTML 文档的同时异步下载脚本。脚本下载完成后,解析会在脚本执行期间被阻止。defer会使浏览器在继续解析 HTML 文档的同时异步下载脚本,然后等待文档解析完成后再运行脚本。
始终对第三方脚本使用 async 或 defer,除非该脚本对于关键渲染路径是必需的。如果脚本需要在加载过程的早期运行(例如某些分析脚本),请使用 async。对于不太重要的资源,例如在网页上呈现的位置低于用户最初看到的位置的视频,请使用 defer。
如果您最关心的是性能,我们建议您等到网页的关键内容加载完毕后再添加异步脚本。我们不建议对 jQuery 等基本库使用 async。
某些脚本必须在不使用 async 或 defer 的情况下加载,尤其是那些对网站至关重要的脚本。这些资源包括网站正常运行所必需的界面库或内容分发网络 (CDN) 框架。
其他脚本在异步加载时则无法正常运行。请查看您使用的所有脚本的文档,并将无法异步加载的所有脚本替换为可以异步加载的替代脚本。请注意,有些第三方会建议同步运行其脚本,即使这些脚本异步运行的效果同样出色。
请注意,async 无法解决所有问题。如果您的网页包含大量脚本(例如用于广告目的的跟踪脚本),那么即使异步加载这些脚本,也无法阻止它们减慢网页加载速度。
使用资源提示缩短连接设置时间
建立与第三方源的连接可能需要很长时间,尤其是在网络速度较慢的情况下,因为网络请求包含多个复杂的组件,包括 DNS 查找和重定向。您可以使用 Resource Hints(例如 )在网页加载过程的早期对托管第三方脚本的网域执行 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 实现高效延迟加载
过去,用于检测元素是否在视口中可见以进行延迟加载的方法很容易出错,并且通常会降低浏览器速度。这些低效的方法通常会监听 scroll 或 resize 事件,然后使用 getBoundingClientRect() 等 DOM API 来计算元素相对于视口的位置。
IntersectionObserver 是一种浏览器 API,可让网页所有者高效检测被观察元素何时进入或离开浏览器的视口。LazySizes 还可选择支持 IntersectionObserver。
延迟加载分析
如果您将分析脚本的加载时间推迟太久,可能会错过有价值的分析数据。幸运的是,有一些策略可用于延迟初始化分析,同时保留早期网页加载数据。
Phil Walton 的博文我在每个网站上使用的 Google Analytics 设置介绍了 Google Analytics 的一种此类策略。
安全地加载第三方脚本
本部分提供了有关如何尽可能安全地加载第三方脚本的指南。
避免使用 document.write()
第三方脚本(尤其是旧版服务的脚本)有时会使用 document.write() 注入和加载脚本。这会带来问题,因为 document.write() 的行为不一致,并且其故障难以调试。
document.write() 问题的解决方法是避免使用它。在 Chrome 53 及更高版本中,Chrome 开发者工具会将 document.write() 的问题使用情况记录到控制台:
document.write() 用法。如果您收到此错误,可以通过查找发送到浏览器的 HTTP 标头来检查网站是否使用了 document.write()。Lighthouse 还可以突出显示仍在使用 document.write() 的任何第三方脚本。
document.write()。谨慎使用跟踪代码管理器
代码是一段代码,可让数字营销团队收集数据、设置 Cookie 或将第三方内容(例如社交媒体 widget)集成到网站中。这些代码会向您的网页添加网络请求、JavaScript 依赖项和其他资源,从而影响网页性能。随着添加的代码越来越多,您就越来越难以最大限度地减少对用户的影响。
为了保持网页加载快速,我们建议您使用 Google 跟踪代码管理器 (GTM) 等跟踪代码管理器。GTM 允许您异步部署代码,这样它们就不会相互阻止加载,从而减少浏览器执行代码所需的网络调用次数,并在其数据层界面中收集代码数据。
使用跟踪代码管理器的风险
虽然跟踪代码管理器旨在简化网页加载,但如果使用不当,反而会通过以下方式减慢加载速度:
- 如果您的跟踪代码管理器中有过多的代码和自动事件监听器,会导致浏览器发出不必要的网络请求,并降低代码快速响应事件的能力。
- 任何拥有凭据和访问权限的人都可以向您的跟踪代码管理器添加 JavaScript。这不仅会增加加载网页所需的昂贵网络请求数量,还可能因不必要的脚本而带来安全风险和其他性能问题。为降低这些风险,我们建议您限制对跟踪代码管理器的访问权限。
避免使用会污染全局范围的脚本
第三方脚本可能会以各种方式意外破坏您的网页:
- 加载 JavaScript 依赖项的脚本可能会使用与您的代码交互不佳的代码污染全局范围。
- 意外更新可能会导致破坏性更改。
- 第三方代码在传输过程中可能会被修改,从而导致在测试和部署网页时表现出不同的行为。
我们建议您定期审核加载的第三方脚本,以检查是否存在不良行为者。您还可以实现自测、子资源完整性和第三方代码的安全传输,以确保网页安全。
缓解策略
以下是一些大规模策略,可最大限度地减少第三方脚本对网站性能和安全性的影响:
沙盒化:考虑在具有
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,建议您阅读以下内容:
- 性能和弹性:对第三方进行压力测试
- 使用 JavaScript 添加互动性
- 第三方脚本的潜在危险
- 第三方脚本如何成为网络上的高性能公民
- Why Fast Matters - CSS Wizardry
- JavaScript 供应链悖论:SRI、CSP 和对第三方库的信任
- 第三方 CSS 不安全
感谢 Kenji Baheux、Jeremy Wagner、Pat Meenan、Philip Walton、Jeff Posnick 和 Cheney Tsai 的审核。