发布时间:2021 年 7 月 29 日
代码是插入到网站中的第三方代码段,通常使用跟踪代码管理器插入。代码最常用于营销和分析。
跟踪代码和跟踪代码管理器对性能的影响因网站而异。跟踪代码管理器可以比作信封:跟踪代码管理器提供了一个容器,但您在其中填充什么内容以及如何使用它,主要取决于您。
在这里,我们将讨论优化代码和跟踪代码管理器以提升性能和 Core Web Vitals 的分析法。虽然本文档引用了 Google 跟踪代码管理器,但其中讨论的许多概念也适用于其他跟踪代码管理器。
对 Core Web Vitals 的影响
跟踪代码管理器通常会间接影响 Core Web Vitals,因为它们会消耗快速加载网页并保持网页响应速度所需的资源。带宽可能会用于为您的网站下载跟踪代码管理器 JavaScript,或用于其后续调用。主线程上的 CPU 时间可能用于评估和执行跟踪代码管理器和代码中包含的 JavaScript。
Largest Contentful Paint (LCP) 在关键网页加载时间期间容易受到带宽争用的影响。此外,阻塞主线程可能会延迟 LCP 呈现时间。
Cumulative Layout Shift (CLS) 可能会受到影响,原因是在首次渲染之前延迟加载关键资源,或者跟踪代码管理器将内容注入网页。
Interaction to Next Paint (INP) 容易受到主线程上的 CPU 争用的影响,我们发现跟踪代码管理器的大小与 INP 得分较低之间存在相关性。
选择合适的代码类型
标签对效果的影响因标签类型而异。一般来说,图片代码(“像素”)的效果最好,其次是自定义模板,最后是自定义 HTML 代码。供应商代码因其允许的功能而异。
请注意,代码的使用方式会极大地影响其对性能的影响。“像素”之所以具有很高的性能,主要是因为这种代码类型的性质对其使用方式施加了严格的限制;自定义 HTML 代码不一定会对性能产生负面影响,但由于它们为用户提供了很大的自由度,因此很容易被滥用,从而对性能产生负面影响。
在考虑代码时,请注意规模:任何单个代码对性能的影响可能微不足道,但如果在同一网页上使用数十或数百个代码,影响可能会变得显著。
并非所有脚本都应使用跟踪代码管理器加载
跟踪代码管理器通常不是加载资源的最佳方式,这些资源会立即实现用户体验的视觉或功能方面,例如 Cookie 通知、主打图片或网站功能。使用跟踪代码管理器加载这些资源通常会延迟其传送。这不利于用户体验,还可能会增加 LCP 和 CLS 等指标。
此外,部分用户会屏蔽跟踪代码管理器。使用跟踪代码管理器实现用户体验功能可能会导致部分用户的网站无法正常运行。
请谨慎使用自定义 HTML 代码
自定义 HTML 代码已存在多年,在大多数网站上都得到了广泛使用。自定义 HTML 代码允许您输入自己的代码,几乎没有限制,因为尽管名称如此,此代码的主要用途是向网页添加自定义 <script> 元素。
自定义 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 旨在用于在服务器响应无关紧要的情况下向 Web 服务器发送少量数据。
const url = "https://example.com/analytics";
const data = JSON.stringify({
event: "checkout",
time: performance.now()
});
navigator.sendBeacon(url, data);
sendBeacon() 的 API 功能有限:它仅支持发出 POST 请求,不支持设置自定义标头。所有现代浏览器都支持该 API。
Fetch API 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 的灵活性要高得多;不过,keepalive 的浏览器支持不如 sendBeacon()。
了解代码的作用
代码通常是按照第三方供应商提供的指南创建的。 如果不清楚供应商的代码有何作用,请考虑咨询知情人士。 征求第三方意见有助于确定代码是否有可能造成性能或安全问题。
我们建议在跟踪代码管理器中为代码添加所有者标签。人们很容易忘记代码的所有者,从而不敢移除代码,以免破坏某些功能!
触发器
简而言之,优化代码触发器通常包括确保不触发不必要的代码,以及选择在业务需求与性能成本之间取得平衡的触发器。
触发器是 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。
尽量减少变量的使用,因为跟踪代码管理器会持续评估变量。移除不再使用的旧变量,以缩减跟踪代码管理器脚本的大小并缩短其处理时间。
代码管理
高效使用代码可降低出现性能问题的风险。
使用数据层
数据层是一个 JavaScript 数组,其中包含有关网页的信息。这些对象包含您要传递给 Google 跟踪代码管理器的所有信息。
数据层还可用于触发代码。
// 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 访问权限。
数据层的性能优势可能并不直观,因为更新数据层会导致 Google 跟踪代码管理器重新评估所有容器变量,并可能触发代码,这需要执行 JavaScript。虽然数据层可能会被滥用,但一般来说,如果数据层似乎是性能问题的根源,则容器本身可能存在性能问题。数据层使这些问题更加明显。
移除重复和未使用的代码
如果代码除了通过跟踪代码管理器注入之外,还包含在网页的 HTML 标记中,则可能会出现重复代码。
未使用的代码应暂停或移除,而不是通过使用特例型触发器进行屏蔽。暂停或移除代码会从容器中移除代码;屏蔽则不会。
移除未使用的代码后,请检查触发器和变量,确定是否也可以将其移除。
暂停的代码会影响容器大小,但总载荷小于代码处于有效状态时的大小。
使用许可名单和拒绝名单
使用许可名单和拒绝名单,针对网页上允许使用的代码、触发器和变量配置高度精细的限制。这可用于帮助强制执行性能最佳实践和其他政策。
允许列表和拒绝列表通过数据层进行配置。
window.dataLayer = [{
'gtm.allowlist': ['<id>', '<id>', ...],
'gtm.blocklist': ['customScripts']
}];
例如,您可以禁止使用自定义 HTML 代码、JavaScript 变量或直接 DOM 访问。这意味着,只能使用像素和预定义代码,并使用数据层中的数据。虽然这具有限制性,但可以实现更高效、更安全的跟踪代码管理器实现。
考虑使用服务器端代码植入
值得考虑改用服务器端代码植入,尤其是对于希望更好地控制其数据的大型网站。服务器端代码植入会从客户端中移除供应商代码,从而将处理工作从客户端分流到服务器。
例如,使用客户端代码植入时,向多个 Google Analytics 账号发送数据需要客户端针对每个端点发起单独的请求。采用服务器端代码植入时,客户端会向服务器端容器发出单个请求,然后数据会从该容器转发到不同的 Google Analytics 账号。
请注意,服务器端代码植入仅适用于部分代码。代码兼容性因供应商而异。
如需了解详情,请参阅服务器端代码植入简介。
容器
跟踪代码管理器通常允许在其设置中包含多个实例(通常称为容器)。一个跟踪代码管理器普通管理者账号中可以控制多个容器。
每个网页仅使用一个容器
在单个网页上使用多个容器可能会导致严重的性能问题,因为它会带来额外的开销和脚本执行。至少,它会复制核心代码本身,因为核心代码是作为容器 JavaScript 的一部分提供的,无法在容器之间重复使用。
很少有多个容器能同时发挥有效作用。不过,在某些情况下,如果控制得当,这种方法也能奏效。例如:
- 包括一个较轻的“早期加载”容器和一个较重的“后期加载”容器,而不是一个大型容器。
- 为技术水平较低的用户使用受限容器,为更复杂的代码使用限制较少但控制更严格的容器。
如果您必须在每个网页上使用多个容器,请按照 Google 跟踪代码管理器指南设置多个容器。
根据需要使用单独的容器
如果您针对多个媒体资源(例如 Web 应用和移动应用)使用跟踪代码管理器,则所用容器的数量可能会提高或降低工作流效率。这也会影响性能。
如果多个网站的用途和结构相似,则可以有效地使用单个容器。例如,虽然品牌的移动应用和 Web 应用可能具有类似的功能,但这些应用可能具有不同的结构,因此通过单独的容器进行管理会更有效。
如果过于广泛地重复使用单个容器,则会迫使您使用复杂的逻辑来管理代码和触发器,从而增加容器的复杂性和大小。
留意容器大小
容器的大小由其代码、触发器和变量决定。 虽然小型容器仍可能会对网页性能产生负面影响,但大型容器几乎肯定会产生负面影响。
在优化代码使用情况时,容器大小不应是最重要的指标。不过,容器大小过大通常是一个警告信号,表明容器未得到妥善维护,并且可能被滥用。
Google 跟踪代码管理器将容器大小限制为 300 KB,并在容器大小达到大小限制的 70% 后发出警告。
大多数网站都应尽量将容器大小控制在限制范围内。相比之下,网站容器的中位数约为 50 KB。 Google 跟踪代码管理器库本身压缩后约为 33 KB。
为容器版本命名
容器版本是容器内容在特定时间点的快照。使用有意义的名称,并附上有意义的更改的简短说明,有助于更轻松地调试未来的性能问题。
标记工作流
请务必管理好代码更改,以免对网页性能产生负面影响。
在部署前进行测试
在部署之前测试代码,以便在发布之前发现性能问题和其他问题。
测试代码时需要考虑的事项包括:
- 代码是否正常运行?
- 该代码是否会导致任何布局偏移?
- 该代码是否会加载任何资源?这些资源有多大?
- 该代码是否会触发长时间运行的脚本?
预览模式
借助预览模式,您可以在实际网站上测试代码更改,而无需先将其部署到公开网站。预览模式包含一个调试控制台,其中会提供代码的相关信息。
在预览模式下运行时,Google 跟踪代码管理器的执行时间会有所不同(略慢),因为在调试控制台中公开信息需要额外的开销。因此,不建议将预览模式下收集的 Web Vitals 测量结果与生产环境中收集的测量结果进行比较。不过,这种差异应该不会影响代码本身的执行行为。
独立测试
另一种测试代码的方法是设置一个空白网页,其中包含一个仅含一个代码(即您要测试的代码)的容器。这种测试设置不太符合实际情况,无法发现某些问题(例如,代码是否会导致布局偏移),但可以更轻松地隔离和衡量代码对脚本执行等操作的影响。了解 Telegraph 如何使用这种隔离方法来提高第三方代码的性能。
监控代码性能
Google 跟踪代码管理器 Monitoring API 可用于收集特定代码的执行时间的相关信息。这些信息会报告给您选择的端点。
如需了解详情,请参阅如何构建 Google 跟踪代码管理器监控器。
需要获得批准才能更改容器
第一方代码通常在部署前会经过审核和测试。 对代码也应如此。
一种方法是添加两步验证,这需要管理员批准容器更改。或者,如果您不想要求进行两步验证,但仍想关注更改,则可以设置容器通知,以便接收有关您选择的容器事件的电子邮件提醒。
定期审核代码使用情况
使用标记时面临的一个挑战是,标记往往会随着时间的推移而累积:标记会被添加,但很少会被移除。定期审核代码是扭转这一趋势的一种方法。执行此操作的理想频率取决于网站代码的更新频率。
为每个代码添加标签,以便明确所有者,从而更轻松地识别谁负责该代码,并确定是否仍需要该代码。
在审核代码时,请记得清理触发器和变量。它们也往往是导致性能问题的原因
如需了解详情,请参阅控制第三方脚本。