您最近是否在 Chrome 的 Play 管理中心内看到过类似以下的警告,并想知道它是什么?
(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 中的插桩,我们了解到,在 2G 网络上,如果网页包含通过 document.write()
插入的第三方脚本,则其加载用时通常是其他网页的 2 倍。
我们对 1% 的 Chrome 稳定版用户进行了为期 28 天的现场试用,仅限使用 2G 连接的用户。我们发现,在 2G 网络上,7.6% 的网页加载包含至少 1 个通过 document.write()
在顶级文档中插入的跨网站解析器阻塞脚本。由于阻止加载这些脚本,我们在这些加载方面看到了以下改进:
- 10% 的网页加载达到了首次内容渲染(向用户直观确认网页正在有效加载),25% 的网页加载达到了完全解析状态,并且重新加载次数减少了 10%,这表明用户的挫败感有所降低。
- 首次内容渲染的平均时间缩短了 21%(缩短了超过 1 秒)
- 将解析网页所需的平均时间缩短了 38%,这相当于将解析时间缩短了近 6 秒,大大缩短了向用户显示重要内容所需的时间。
考虑到这些数据,从版本 55 开始,Chrome 会在检测到这种已知不良模式时代表所有用户进行干预,具体做法是更改 document.write()
在 Chrome 中的处理方式(请参阅 Chrome 状态)。具体而言,如果满足以下所有条件,Chrome 将不会执行通过 document.write()
注入的 <script>
元素:
- 用户的网速较慢,特别是在使用 2G 网络时。(未来,此变更可能会扩展到网速较慢的其他用户,例如 3G 网速较慢或 Wi-Fi 网速较慢的用户。)
document.write()
位于顶级文档中。此干预措施不适用于 iframe 中的 document.written 脚本,因为它们不会阻止主页面呈现。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 在发送此警告时会忽略连接条件),则警告将如下所示:
在 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 中只显示了一条警告。 (Beta 版于 2016 年 7 月发布。我们预计将于 2016 年 9 月向所有用户推出稳定版。)
我们将从 Chrome 54 开始,暂时阻止向 2G 用户注入的脚本。Chrome 54 预计将于 2016 年 10 月中旬为所有用户提供稳定版本。如需了解更多动态,请参阅 Chrome 状态条目。
随着时间的推移,我们希望在任何用户的连接速度缓慢(例如 3G 或 Wi-Fi 速度缓慢)时进行干预。请按照此Chrome 状态条目中的说明操作。
希望了解更多信息?
如需了解详情,请参阅下面列出的其他资源: