您最近是否在 Chrome 的 Developer Console 中看到了如下所示的警告,并想知道这是什么?
(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.
可组合性是 Web 的强大功能之一,它让我们能够轻松与第三方构建的服务集成,从而构建出色的新产品!可组合性的一个缺点是,它暗示着对用户体验共同承担责任。如果集成不够理想,则会对用户体验产生负面影响。
导致性能不佳的一个已知原因是在页面内使用 document.write()
,尤其是那些注入脚本的用途。如下所示,它虽然无害,但可能会给用户带来真正的问题。
document.write('<script src="https://example.com/ad-inject.js"></script>');
浏览器必须先通过解析 HTML 标记来构建 DOM 树,然后才能呈现网页。每当解析器遇到某个脚本时,就必须先停止并执行该脚本,然后才能继续解析 HTML。如果脚本动态注入另一个脚本,则解析器会被迫等待更长时间,以便下载资源,这可能导致一次或多次网络往返,并延迟首次呈现网页的时间
对于网速较慢(例如使用 2G 网络)的用户,通过 document.write()
动态注入的外部脚本可能会使主页面内容的显示延迟几十秒,或者导致页面无法加载或因用户等待太久而放弃。根据 Chrome 中的插桩,我们发现,对于通过 document.write()
插入第三方脚本的网页,其加载速度通常是其他 2G 网页的两倍。
我们从 1% 的 Chrome 稳定版用户中收集了 28 天的现场试验数据,仅限使用 2G 连接的用户。我们发现,2G 上所有网页加载的 7.6% 包含至少一个通过 document.write()
插入顶级文档中的跨网站、解析器阻止脚本。由于阻止了这些脚本的加载,我们发现这些加载得到了以下改进:
- 达到首次内容渲染(向用户显示网页正在有效加载)的页面加载次数增加了 10%,达到完全解析状态的页面加载次数增加了 25%,重新加载次数减少了 10%,这表明用户的不满减少了。
- 距离 First Contentful Paint 的平均时间缩短 21%(缩短了 1 秒以上)
- 将解析网页所需的平均时间缩短了 38%,这相当于将解析时间缩短了近 6 秒,大大缩短了向用户显示重要内容所需的时间。
考虑到这些数据,从版本 55 开始,当我们检测到这种已知不良模式时,Chrome 会更改 document.write()
在 Chrome 中的处理方式(请参阅 Chrome 状态),代表所有用户进行干预。具体而言,当满足以下所有条件时,Chrome 不会执行通过 document.write()
注入的 <script>
元素:
- 用户的网速较慢,特别是在使用 2G 网络时。(将来,此变化可能会在网络连接速度较慢(例如 3G 网络速度或 Wi-Fi 速度较慢)时影响其他用户。)
document.write()
位于顶级文档中。这项干预不适用于 iframe 中的 document.Write 脚本,因为它们不会阻止主页面的呈现。document.write()
中的脚本阻止了解析器。具有“async
”或“defer
”属性的脚本仍会执行。- 脚本未托管在同一网站上。换句话说,Chrome 不会干预具有匹配 eTLD+1 的脚本(例如,在 www.example.org 上插入 js.example.org 上托管的脚本)。
- 该脚本尚不在浏览器 HTTP 缓存中。缓存中的脚本不会产生网络延迟,并且仍会执行。
- 对页面的请求并非重新加载页面。如果用户触发了重新加载,Chrome 不会进行干预,而是会照常执行该网页。
第三方代码段有时会使用 document.write()
加载脚本。幸运的是,大多数第三方都提供异步加载替代方案,以允许第三方脚本加载,而不会阻止网页上的其余内容显示。
如何解决此问题?
这个简单的答案是不使用 document.write()
注入脚本,我们维护着一组支持异步加载器的已知服务,建议您经常进行检查。
如果您的提供商不在列表中,并且支持异步脚本加载,请告知我们,我们可以更新页面以帮助所有用户。
如果您的提供商不支持将脚本异步加载到网页中,我们建议您与对方联系,并告诉我们他们将受到什么影响。
如果您的提供程序提供了包含 document.write()
的代码段,您可以向脚本元素添加 async
属性,或者通过 DOM API(例如 document.appendChild()
或 parentNode.insertBefore()
)添加脚本元素。
如何检测您的网站何时受到影响
决定是否强制执行该限制的标准有很多,那么您如何知道自己是否受到影响呢?
检测用户何时正在使用 2G
若要了解这项变更的潜在影响,您首先需要了解将有多少用户会使用 2G 网络。您可以使用 Chrome 中提供的 Network Information API 检测用户当前的网络类型和速度,然后向您的分析系统或真实用户指标 (RUM) 系统发送浮动通知。
if(navigator.connection &&
navigator.connection.type === 'cellular' &&
navigator.connection.downlinkMax <= 0.115) {
// Notify your service to indicate that you might be affected by this restriction.
}
在 Chrome 开发者工具中捕获警告
从 Chrome 53 开始,开发者工具会针对有问题的 document.write()
语句发出警告。具体来说,如果 document.write()
请求满足条件 2 到 5(Chrome 在发送此警告时忽略连接条件),警告将如下所示:
![文档写入警告。](https://developer.chrome.google.cn/static/blog/removing-document-write/image/document-write-warning-ed640bb59480d.png?authuser=5&hl=sk)
在 Chrome 开发者工具中看到警告是很好的做法,但如何大规模地检测到这种情况呢?您可以检查干预发生时发送到您的服务器的 HTTP 标头。
检查脚本资源中的 HTTP 标头
通过 document.write
插入的脚本被屏蔽后,Chrome 会将以下标头发送给请求的资源:
Intervention: <https://shorturl/relevant/spec>;
当发现通过 document.write
插入的脚本时,如果脚本在不同情况下可能遭到阻止,Chrome 可能会发送:
Intervention: <https://shorturl/relevant/spec>; level="warning"
干预标头将作为脚本的 GET 请求的一部分发送(如果是实际干预,则以异步方式发送)。
未来将会怎样?
最初的计划是在检测到满足条件时执行此干预。我们从 Chrome 53 的 Developer Console 中只显示了一条警告。 (测试版于 2016 年 7 月推出。我们预计将于 2016 年 9 月向所有用户推出稳定版。)
我们将从 Chrome 54 开始,暂时阻止向 2G 用户注入的脚本。Chrome 54 预计将于 2016 年 10 月中旬为所有用户提供稳定版本。如需了解更多更新,请查看 Chrome 状态条目。
随着时间的推移,我们希望在任何用户的连接速度较慢(即 3G 或 Wi-Fi 速度较慢)时进行干预。按照这条 Chrome 状态条目操作。
希望了解更多信息?
如需了解详情,请参阅下面列出的其他资源: