我让网站的分析脚本等页面先到。代价是什么
在这个网站上打开一篇文章,读者下载的东西里有 60% 是 Google 的分析脚本,而且它们在文章还没到齐时就开始抢路。我让它们等到页面空闲、或者读者第一次触碰页面时才加载。这里是前后的数字、那段代码、可能少算的访问,以及测速工具看不到的那一部分。
其他语言版本 English
Google 原来占了一篇文章多少
2026 年 10 月 2 日早上,这个网站的每一个文章页面一共 492 到 494 KB,其中 297 KB 来自 Google。
那天稍早,我拿掉了 Cookie 横幅。分析工具从此对每一位读者都加载,页脚的 Cookie 链接里可以关掉;欧洲经济区、英国和瑞士的读者默认是关的。横幅在的时候,Google 要等读者点了「允许」才加载。横幅一拿掉,每个页面一开始加载,两个脚本就跟着启动:Tag Manager 的容器 gtm.js,大约 122 KB;Google Analytics 的标签 gtag/js,大约 174 KB。
我用 Lighthouse 的手机模式测了嘛嘛档那篇文章,每个页面跑两次。英文版是 94 分和 75 分,中文版是 95 分和 92 分,首页是 68 分和 56 分。
读者真正来读的那些字,只占手机下载量的一小部分。
要紧的是顺序,不只是大小
标了 async 的脚本不会挡住页面绘制,但它还是在跟页面抢。手机上,Google 的文件和文章自己的图片、字体共用一条连接;文件到了之后,又要在同一条主线程上运行,而那条线程正忙着把文字排出来。
分析工具不需要排第一。它只需要到一次,而且及时到,把这次访问记下来。
所以问题不是要不要留着 Google,而是什么时候去请它来。
改动:等空闲,或者等第一次触碰
从 10 月 2 日起,规则很简单。页面先加载完。然后,两件事里先发生的那一件去请求 gtm.js:浏览器说它空闲了,或者读者动了一下。
具体来说:
- 同意设置的默认值,以及读者之前存下的选择,一开始就立刻推送,跟以前一样。任何数据都不会在错误的同意状态下发出去。
- 页面的
load事件之后,脚本请浏览器在空闲时通知它,最多等 2,000 毫秒。Safari 没有空闲回调,所以在那里是load之后等 1,500 毫秒。 - 如果读者先滚动、点按、点击、转滚轮或者按键,gtm.js 就在那一刻请求。
- 哪一件先发生就算哪一件,其余的全部取消。每次访问只发生一次,读者跳到站内另一个页面时也一样。
- 关掉了分析的读者,不会向 Google 请求任何东西。
核心就是下面这段,从这个网站实际运行的脚本里精简出来:
const INTERACTIONS = ['pointerdown', 'keydown', 'touchstart', 'scroll', 'wheel'];
const LISTEN = { capture: true, passive: true };
let loaded = false;
function loadGtm() {
if (loaded) return;
loaded = true;
INTERACTIONS.forEach((type) => window.removeEventListener(type, loadGtm, LISTEN));
window.dataLayer.push({ 'gtm.start': Date.now(), event: 'gtm.js' });
const s = document.createElement('script');
s.async = true;
s.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX';
document.head.appendChild(s);
}
function waitForIdle() {
if ('requestIdleCallback' in window) requestIdleCallback(loadGtm, { timeout: 2000 });
else setTimeout(loadGtm, 1500);
}
INTERACTIONS.forEach((type) => window.addEventListener(type, loadGtm, LISTEN));
if (document.readyState === 'complete') waitForIdle();
else window.addEventListener('load', waitForIdle, { once: true });
有两个细节要紧。gtm.start 那一行和插入脚本放在同一个函数里,所以 Tag Manager 自己的计时,是从文件真正被请求的那一刻开始。还有,监听器都是被动的(passive),永远不会拖慢滚动。
我用两个 AI 会话工作,一个 Brain 负责规划,一个 Hand 负责建造。拿掉中文网页字体之后,Google 成了文章页面上最重的东西,于是 Brain 提了这个改动。Hand 把它做出来,每一种情况都写了测试,包括在 Google 加载之前关掉分析、再在同一个页面上打开。我是先读清楚它要我付出什么,才点头的,那部分在下面。
前后对比
下面是线上网站的 Lighthouse 手机模式中位数,同一天,改动前跑两次,改动后跑三次。只有两次的时候,改动前的「中位数」就是两次的平均。
| 改动前 | 改动后 | |
|---|---|---|
| 英文文章,分数 | 84.5 | 98 |
| 英文文章,最大内容绘制(LCP) | 3.95 秒 | 1.6 秒 |
| 英文文章,总阻塞时间(TBT) | 125 毫秒 | 50 毫秒 |
| 中文文章,分数 | 93.5 | 97 |
| 中文文章,最大内容绘制(LCP) | 2.45 秒 | 2.1 秒 |
| 中文文章,总阻塞时间(TBT) | 165 毫秒 | 60 毫秒 |
| 首页,分数 | 62 | 68 |
| 首页,最大内容绘制(LCP) | 5.65 秒 | 5.7 秒 |
英文那一行要小心读。它的「改动前」是 94 和 75 的平均,而 75 只是一次跑得慢。老实的总结是:改动前,文章页面多数在 90 多分,中间夹着几次差的;改动后,大多数时候是 97 到 99 分,页面被卡住的时间少了一半或更多。
首页几乎没动,原因我知道。首页跑着一个 3D 场景,它的代价比分析工具大,那一笔我另外写过。
在真实浏览器里全新打开一次:页面在 692 毫秒加载完,gtm.js 在 718 毫秒请求,页面浏览在 1,222 毫秒送到 Google。同一天早上用旧代码:gtm.js 在 659 毫秒请求,那时页面还没加载完,页面浏览在 1,212 毫秒发出。在快的网络上,页面浏览发出的时间差不多。变的是,Google 不再趁页面还在路上时就开始挤。
测速工具看不到的那一部分
Lighthouse 在网络安静下来时就结束测量。如果这发生在空闲那一刻之前,Google 根本不会出现在测试里。
改动后的九次测试里,有两次就是这样。一次英文测试总共 195 KB,里面完全没有 Google。另一次只有 gtm.js,122 KB。真实的读者还是会下载全部 297 KB,只是排在页面之后。
所以,实验室分数变好的一部分,是实验室没有待够久。这不是撤回改动的理由:读者的页面现在确实先到了。但这是一个理由,不要拿最好的那一次来说事,而是更相信上面的中位数和浏览器里的实际时间,胜过任何一次单独的分数。
还有一次测试,说明了为什么一次不算数。改动后首页的第一次测试是 45 分,第一段文字过了 22.9 秒才出现。页面上什么都没变,只是网络坏了一分钟。
代价是什么
代价是很短的访问。读者打开一个页面,一两秒内没有滚动、点按或按键就离开,可能在 Google 被请来之前就走了,这次访问就不会被算到。
在快的网络上,这个空档很小:页面加载完大约 30 毫秒,空闲就到了。在慢的手机上会长一些。我不知道这样少算了多少次访问,也没办法知道,因为分析工具算不到它从没见过的访问。这个我接受。这个网站是写来读的,一秒内一动不动就离开的人,什么也没读到。
它没有让我付出的:
- Google 到达之前推送的事件,会在队列里等着,Google 一到就读取。
- 跳到站内另一个页面,不会重复加载。第二个页面的浏览照样记下。
- 关掉了分析的读者,仍然什么都不发送。改动后我重新加载、滚动、点击、按键检查过:对 Google 的请求是零。
如果你投广告、要算转化,你的答案可能跟我不一样。花钱买来、一秒就走的访问,也还是花了钱的访问。
怎么在你自己的网站上做
一个下午就能试,同一个下午就能量出结果。
- 先量。用 Lighthouse 手机模式在一篇文章页面上跑三次,记下来自 googletagmanager.com 和 google-analytics.com 的 KB 数。
- 把页面头部的 Tag Manager 代码段拿掉,但
dataLayer和同意设置的默认值,仍然放在页面前面。 - 在你自己的脚本文件里加一个像上面那样的触发器;如果你的安全策略不允许内联脚本(这个网站就不允许),就不要写成内联代码段。
- 在真实浏览器里确认页面浏览还能送到:打开开发者工具,进入 Network(网络),筛选
collect,先试一次全新打开、什么都不碰,再试一次滚动。 - 确认关掉分析后,仍然什么都不发送。
- 再量一次,跑三次,比较中位数,不要比你最好的那一次。
- 想清楚可能少算的短访问,对你这类网站重不重要。
常见问题
延迟加载 Google Tag Manager 能让网页变快吗?
通常能改善衡量页面本身多快出现的那些数字。在这个网站上,一篇英文文章在手机上的最大内容绘制中位数从 3.95 秒降到 1.6 秒,页面被卡住的时间从 125 毫秒降到 50 毫秒。Google 的文件还是会下载,只是排在页面之后。
延迟加载 Google Analytics 会少算数据吗?
可能会少算很短的访问:读者在一两秒内没有滚动、点按或按键就离开。读者留下来、或者碰过页面的访问,照样会被算到,之前推送的事件也会在队列里等着。少算了多少次,你量不出来,因为分析工具根本看不到它们。
应该等浏览器空闲,还是等读者第一次互动?
两个都用,哪个先到就用哪个。只等互动,会漏掉每一个不滚动、只是静静读的读者。只等空闲,在忙碌的手机上可能来得太晚。这个网站用的是:页面加载完后的空闲回调,最多等 2,000 毫秒;浏览器没有空闲回调时,用 1,500 毫秒的计时器;再加上第一次滚动、点按、点击、转滚轮或按键。
为什么延迟加载之后,Lighthouse 有时完全看不到 Google Tag Manager?
因为 Lighthouse 在网络安静下来时就停止测量,而这可能发生在空闲那一刻之前。这个网站的九次测试里,有两次在 Google 加载之前就结束了。真实的读者还是会下载这些文件。比较几次测试的中位数,并在浏览器里看实际时间,不要只信一次分数。