针对 Core Web Vitals 优化代码和跟踪代码管理器。
代码是指通常通过跟踪代码管理器插入到网站中的第三方代码段。代码最常用于营销和分析。
代码和跟踪代码管理器对性能的影响因网站而异。 跟踪代码管理器可以比作一个信封:跟踪代码管理器提供了一个容器,但您在其中填充什么以及使用方法则主要取决于您。
本文介绍了一些技巧,针对性能和网页指标优化代码和跟踪代码管理器。虽然本文引用的是 Google 跟踪代码管理器,但其中讨论的许多理念也适用于其他跟踪代码管理器。
对核心网页指标的影响
跟踪代码管理器通常会消耗所需的资源,以快速加载网页并使其保持快速响应,从而间接影响核心网页指标。下载您网站的跟踪代码管理器 JavaScript 或进行后续调用时,可能会花费带宽。主线程上的 CPU 时间可用于评估和执行跟踪代码管理器和代码中包含的 JavaScript。
在关键网页加载期间,Largest Contentful Paint (LCP) 容易受到带宽争用。此外,阻塞主线程可能会延迟 LCP 呈现时间。
受累积布局偏移 (CLS) 的影响,可能会在首次呈现之前延迟加载关键资源,或者跟踪代码管理器向网页注入内容。
Interaction to Next Paint (INP) 很容易在主线程上发生 CPU 争用,并且我们发现跟踪代码管理器的大小与较低的 INP 得分之间存在关联。
代码类型
代码对效果的影响因代码类型而异。一般来说,图片标记(“像素”)效果最佳,其次是自定义模板,最后是自定义 HTML 代码。供应商代码因其允许的功能而异。
不过请注意,代码使用方式会极大地影响代码对效果的影响。“像素”的性能非常高,很大程度上是因为此代码类型的本质对其使用方式施加了严格的限制;自定义 HTML 代码不一定总是影响性能,但由于它们为用户提供的自由程度高,因此它们很容易被滥用,导致性能不佳。
在考虑代码时,请注意规模化:任何单个代码对性能的影响可能微乎其微,但在同一网页上使用数十或数百个代码时,影响可能会变得非常显著。
并非所有脚本都应使用跟踪代码管理器加载
如果要加载那些能直接带来用户体验的视觉或功能元素(例如 Cookie 通知、主打图片或网站功能)的资源,跟踪代码管理器通常就不会是很好的加载机制。使用跟踪代码管理器加载这些资源通常会延迟其投放。这不利于用户体验,并且还可能会增加 LCP 和 CLS 等指标。此外,请注意,有些用户会屏蔽跟踪代码管理器。如果使用跟踪代码管理器来实现用户体验功能,可能会导致某些用户的网站损坏。
请慎重使用自定义 HTML 代码
自定义 HTML 代码已存在多年,在大多数网站上十分常见。自定义 HTML 标记可让您输入自己的代码,几乎没有什么限制,因为此标记的主要用途是将自定义 <script>
元素添加到页面中,尽管名称如此。
自定义 HTML 代码可通过多种方式使用,并且其性能影响有很大差异。在衡量网站性能时,请注意,大多数工具会将自定义 HTML 代码的性能影响归因于注入自定义 HTML 代码的跟踪代码管理器,而不是代码本身。
自定义 HTML 代码可将元素插入到周围的页面中。将元素插入页面可能会导致性能问题,在某些情况下,还会导致布局偏移。
- 在大多数情况下,如果将元素插入页面中,浏览器必须重新计算页面上每项内容的大小和位置,此过程称为布局。单个布局对性能的影响微乎其微,但如果过度发生,就可能成为性能问题的根源。这种现象对低端设备和具有大量 DOM 元素的网页的影响更大。
- 如果在周围区域已渲染之后将可见页面元素插入 DOM,则可能会导致布局偏移。这种现象不是跟踪代码管理器独有的,但由于代码通常比网页的其他部分更晚加载,因此在周围的网页呈现完毕后插入 DOM 就很常见。
考虑使用自定义模板
自定义模板支持与自定义 HTML 代码相同的一些操作,但基于 JavaScript 的沙盒化版本构建而成,该版本为脚本注入和像素注入等常见用例提供了 API。顾名思义,这些模板允许创建模板,高级用户可在构建此类模板时充分考虑性能。然后,技术水平较低的用户可以使用该模板。这通常比提供完整的自定义 HTML 访问权限更安全。
由于对自定义模板施加的限制更为严格,因此这些代码出现性能或安全问题的可能性会大大降低;不过,出于同样的原因,自定义模板并非适用于所有用例。
正确注入脚本
使用跟踪代码管理器注入脚本是一种很常见的用例。为此,建议您使用自定义模板和 injectScript
API。
如需了解如何使用 injectScript API 转换现有自定义 HTML 代码,请参阅转换现有代码。
如果您必须使用自定义 HTML 代码,请注意以下事项:
- 应使用用于下载外部文件(例如
<script src="external-scripts.js">
)的脚本标记加载库和大型第三方脚本,而不是直接将脚本内容复制粘贴到该标记中。虽然不使用<script>
标记免去了下载脚本内容的单独往返过程,但这种做法会增加容器大小并阻止浏览器单独缓存脚本。 - 许多供应商建议将其
<script>
标记放在<head>
的顶部。不过,对于通过跟踪代码管理器加载的脚本,通常没必要这样做:在大多数情况下,浏览器在执行跟踪代码管理器之前就已完成对<head>
的解析。
使用像素
在某些情况下,第三方脚本可替换为图片或 iframe“像素”。与基于脚本的对应像素相比,像素支持的功能可能较少,因此通常被视为不太首选的实现方式。不过,在跟踪代码管理器内使用时,像素可以更加动态,因为它们可以在触发器上触发并传递不同的变量。这些代码是性能最高且最安全的代码类型,因为此类代码在触发后无需执行 JavaScript。像素的资源大小非常小(小于 1 KB),不会导致布局偏移。
请与您的第三方提供商联系,详细了解他们对像素的支持情况。此外,您还可以尝试检查其代码中是否包含 <noscript>
标记。如果供应商支持像素,通常会将其包含在 <noscript>
标记中。
像素的替代方案
像素之所以受欢迎,很大程度上是因为像素曾是在服务器响应不相关的情况下发出 HTTP 请求最便宜且最可靠的方法之一(例如,在将数据发送到分析工具时)。navigator.sendBeacon()
和 fetch()
keepalive
API 旨在应对相同的用例,但可以说比像素更可靠。
继续使用像素没有问题 - 这类像素受到良好支持,对性能的影响微乎其微。不过,如果您要构建自己的信标,则可以考虑使用以下 API。
sendBeacon()
navigator.sendBeacon()
API 用于在服务器响应无关紧要的情况下将少量数据发送到网络服务器。
const url = "https://example.com/analytics";
const data = JSON.stringify({
event: "checkout",
time: performance.now()
});
navigator.sendBeacon(url, data);
sendBeacon()
具有有限的 API:它仅支持发出 POST 请求,不支持设置自定义标头。所有现代浏览器都支持此功能。
fetch() keepalive
keepalive
是一个标志,它允许使用 Fetch API 发出非阻塞请求,例如事件报告和分析。若要使用它,您需要在传递给 fetch()
的参数中添加 keepalive: true
。
const url = "https://example.com/analytics";
const data = JSON.stringify({
event: "checkout",
time: performance.now()
});
fetch(url, {
method: 'POST',
body: data,
keepalive: true
});
如果 fetch() keepalive
和 sendBeacon()
看起来非常相似,则是因为两者非常相似。事实上,在 Chromium 浏览器中,sendBeacon()
现在是基于 fetch()
keepalive
构建的。
在 fetch() keepalive
和 sendBeacon()
之间进行选择时,请务必考虑您需要的功能和浏览器支持。fetch() API 要灵活得多;不过,与 sendBeacon()
相比,keepalive
的浏览器支持更少。
获取澄清说明
代码通常按照第三方供应商提供的指南创建。如果您不清楚供应商的代码的用途,请考虑咨询知道相应代码的人。 通过征求第二意见有助于确定代码是否有可能造成性能或安全问题。
我们还建议您在跟踪代码管理器中通过所有者标记代码。您很容易忘记一个标记的所有者,并害怕将它移除,以防万一!
触发器
概括来讲,优化代码触发器通常包括确保不超过必要的代码触发次数,以及选择在业务需求与性能成本之间取得平衡的触发器。
触发器本身是 JavaScript 代码,会增加跟踪代码管理器的大小和执行成本。虽然大多数触发器都很小,但累积影响可能会越来越大。例如,拥有大量点击事件或计时器触发器可能会大幅增加跟踪代码管理器的工作负载。
选择合适的触发事件
代码对性能的影响不是固定的:一般来说,代码触发时间越早,对性能的影响就越大。资源在网页初始加载期间通常会受到限制,因此加载或执行特定资源(或代码)会占用其他资源中的资源。
虽然请务必为所有代码选择合适的触发器,但对于加载大型资源或执行较长脚本的代码尤为重要。
代码可通过网页浏览触发(通常是 Page load
、DOM Ready
、Window Loaded
),或根据自定义事件触发。为避免影响网页加载,建议在 Window Loaded
之后触发非必需代码。
使用自定义事件
借助自定义事件,您可以触发触发器来响应 Google 跟踪代码管理器的内置触发器未涵盖的网页事件。例如,许多代码使用网页浏览触发器;但是,在许多网页上,DOM Ready
到 Window Loaded
之间的时间段可能会很长,因而在代码触发时可能很难进行微调。自定义事件为此问题提供了解决方案。
如需使用自定义事件,请先创建一个自定义事件触发器,并将代码更新为使用此触发器。
如需触发触发器,请将相应的事件推送到数据层。
// Custom event trigger that fires after 2 seconds
setTimeout(() => {
dataLayer.push({
'event' : 'my-custom-event'
});
}, 2000);
使用特定的触发条件
使用特定的触发条件有助于避免不必要地触发代码。虽然可以采用多种方式来应用这一概念,但最简单但最有用的一项做法是确保代码仅在实际使用的网页上触发。
此外,您还可以将内置变量整合到触发条件中,以限制代码触发。
但请注意,具有复杂的触发条件或异常本身需要处理时间,因此不要使其过于复杂。
在适当的时间加载跟踪代码管理器
调整跟踪代码管理器本身的加载时间会对性能产生重大影响。无论触发器如何配置,只有在跟踪代码管理器加载后,才能触发。虽然为单个代码选择良好的触发器很重要(如上所述),但鉴于单项决策将影响网页上的所有代码,在跟踪代码管理器中尝试不同的触发器通常能够产生同等甚至更大的影响。
稍后加载跟踪代码管理器还会增加一层控制,并且可以避免日后出现性能问题,因为这可以防止跟踪代码管理器用户无意中过早加载代码,而没有意识到这可能会造成的影响。
变量
变量允许从网页读取数据。它们在触发器和代码本身中都很有用。
与触发器一样,变量会导致将 JavaScript 代码添加到跟踪代码管理器中,因此可能会导致性能问题。变量可以是相对简单的内置类型,可以读取网址、Cookie、数据层或 DOM 等部分内容。或者,也可以是功能基本无限的自定义 JavaScript。
由于变量需要由跟踪代码管理器持续进行评估,因此请尽量简化变量。移除不再用于缩减跟踪代码管理器脚本大小及其使用的处理时间的旧变量。
跟踪代码管理
有效使用代码可降低出现性能问题的风险。
使用数据层
数据层“包含您希望传递给 Google 跟踪代码管理器的所有信息”。具体而言,它是一个包含页面相关信息的 JavaScript 对象的数组。它还可用于触发代码。
// Contents of the data layer
window.dataLayer = [{
'pageCategory': 'signup',
'visitorType': 'high-value'
}];
// Pushing a variable to the data layer
window.dataLayer.push({'variable_name': 'variable_value'});
// Pushing an event to the data layer
window.dataLayer.push({'event': 'event_name'});
虽然 Google 跟踪代码管理器也能在没有数据层的情况下使用,但我们强烈建议使用它。借助数据层,可以将第三方脚本正在访问的数据整合到一个位置,从而更好地了解其使用情况。除此之外,这还有助于减少冗余的变量计算和脚本执行。使用数据层还可控制代码访问的数据,而不是授予完整的 JavaScript 变量或 DOM 访问权限。
移除重复和未使用的代码
如果除了通过跟踪代码管理器注入代码之外,网页的 HTML 标记中还包含代码,则可能会出现重复的代码。
应使用触发器异常来暂停或移除未使用的代码,而不应将其屏蔽。暂停或移除代码会将代码从容器中移除;屏蔽操作不会将代码从容器中移除。
移除未使用的代码后,您还应检查触发器和变量,看看是否只有这些代码使用其中任何代码可以移除。
使用允许和拒绝列表
通过允许和拒绝列表,您可以针对网页上允许的代码、触发器和变量配置高度精细的限制。这可用于帮助强制执行性能最佳实践和其他政策。
允许和拒绝名单通过数据层进行配置。
window.dataLayer = [{
'gtm.allowlist': ['<id>', '<id>', ...],
'gtm.blocklist': ['customScripts']
}];
例如,您可以禁止任何自定义 HTML 代码、JavaScript 变量或直接进行 DOM 访问。这意味着,数据层中的数据只能使用像素和预定义代码。虽然这种方法存在一定限制,但可以提高跟踪代码管理器实现的性能和安全性。
考虑使用服务器端代码植入
改用服务器端代码植入并非易事,但值得考虑,尤其是对于希望更好地控制数据的大型网站。服务器端代码植入会从客户端中移除供应商代码,并随之将处理任务从客户端分流到服务器。
例如,使用客户端代码植入时,要将数据发送到多个分析帐号,客户端必须为每个端点发起单独的请求。相比之下,使用服务器端代码植入时,客户端会向服务器端容器发出单个请求,然后从那里将这些数据转发到不同的 Google Analytics(分析)帐号。
请注意,服务器端代码植入仅适用于部分代码;代码兼容性因供应商而异。
如需了解详情,请参阅服务器端代码植入简介。
容器
跟踪代码管理器通常允许其设置中存在多个实例或“容器”。这样,您就可以在一个跟踪代码管理器帐号中控制多个容器。
每个页面只能使用一个容器
在单个网页上使用多个containers可能会造成严重的性能问题,因为这会产生额外的开销和脚本执行。至少它与核心代码本身重复,因为它作为容器的 JavaScript 的一部分提供,因此无法在容器之间重复使用。
很少有效地使用多个容器。不过,在某些情况下,如果控制得当,这种方法也可奏效,包括:
- 使用较轻的“提前加载”容器和较重的“稍后加载”容器,而不是一个大型容器。
- 提供一个供技术较少的用户使用的受限容器,以及一个限制较少但控制更严格的容器,用于存放无法在受限容器中使用的代码。
如果每个网页必须使用多个容器,请按照 Google 跟踪代码管理器指南设置多个容器。
根据需要使用单独的容器
如果您针对多个媒体资源(例如,Web 应用和移动应用)使用跟踪代码管理器,则使用的容器数量有益或损害工作流效率。它还可能会影响效果。
一般来说,如果网站的使用方式和结构相似,那么单个容器可以跨多个网站有效使用。例如,虽然一个品牌的移动应用和 Web 应用可能提供的功能类似,但这些应用的结构很可能是不同的,因此可以通过单独的容器进行更有效地管理。
如果尝试过于宽泛地重复使用单个容器,通常会强制采用复杂的逻辑来管理代码和触发器,从而增加容器的复杂性和大小。
关注容器大小
容器的大小由其代码、触发器和变量决定。虽然小型容器可能仍会对网页性能产生负面影响,但大型容器肯定会受到影响。
在优化代码使用时,容器大小不应作为标杆;但是,容器大小较大通常意味着警告信号,表明容器未得到很好的维护,甚至可能遭到滥用。
Google 跟踪代码管理器会限制容器大小不超过 200 KB,并且会在容器大小达到 140 KB 时发出警告。不过,大多数网站都应该力求保持其容器比这个大小小得多。从角度来看,网站容器的中间值大约为 50 KB。
如需确定容器的大小,请查看 https://www.googletagmanager.com/gtag/js?id=YOUR_ID
返回的响应的大小。此响应包含 Google 跟踪代码管理器库以及容器的内容。Google 跟踪代码管理器库本身的压缩后大小约为 33 KB。
为容器版本命名
容器版本是容器内容在特定时间点的快照。使用有意义的名称,并在内部添加有意义的更改的简短说明,这对您可以更轻松地调试未来的性能问题大有帮助。
代码植入工作流
管理对代码所做的更改非常重要,这样可确保这些更改不会对网页性能产生负面影响。
在部署前测试代码
在部署之前对代码进行测试有助于在发布前发现问题(性能等方面)。
测试代码时的注意事项包括:
- 代码能否正常工作?
- 此标记是否会导致任何布局偏移?
- 该代码是否加载任何资源?这些资源的规模有多大?
- 代码是否会触发长时间运行的脚本?
预览模式
利用预览模式,您可以在实际网站上测试代码更改,而无需先将更改公开发布。预览模式包含一个调试控制台,可提供关于代码的信息。
在预览模式下运行时,Google 跟踪代码管理器的执行时间会有所不同(稍慢),这是因为在调试控制台中显示信息需要额外的开销。因此,不建议将预览模式下收集的网页指标测量结果与在生产环境中收集的网页指标测量结果进行比较。不过,这种差异应该不会影响代码本身的执行行为。
独立测试
测试代码的另一种方法是设置一个空网页,其中包含的容器只包含一个代码(您要测试的代码)。这种测试设置不太现实,不会发现一些问题(例如,代码是否会导致布局偏移),但可让您更轻松地隔离和衡量代码对脚本执行等因素的影响。了解 Telegraph 如何利用这种隔离方法提高第三方代码的性能。
监控代码效果
Google 跟踪代码管理器的 Monitoring API 可用于收集有关特定代码的执行时间的信息。此信息将报告至您选择的端点。
如需了解详情,请参阅如何构建 Google 跟踪代码管理器监控器。
容器更改需要批准
第一方代码通常需要在部署之前接受审核和测试,- 请一视同仁地对待您的代码。添加两步验证(需要管理员批准才能更改容器)就是一种方法。或者,如果您不想进行两步验证,但仍想关注更改,则可以设置容器通知,以接收有关您选择的容器事件的电子邮件提醒。
定期审核代码使用情况
使用代码时遇到的一大挑战是,代码往往会随着时间的推移而累积:代码会被添加,但很少被移除。定期审核代码是逆转此趋势的一种方法。理想的频率取决于网站代码的更新频率。
通过标记每个代码,使所有者显而易见,从而更轻松地识别谁响应了该代码,并可以确定是否仍需要该代码。
审核代码时,也别忘了清理触发器和变量。它们也很容易导致性能问题。
如需了解详情,请参阅控制第三方脚本。