您最近是否在 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 秒的时间,从而显著缩短了显示对用户重要的内容所需的时间。
有了这些数据,从 Chrome 55 开始,当我们检测到这种已知的恶意模式时,Chrome 会代表所有用户进行干预,方法是更改 Chrome 中处理 document.write()
的方式(请参阅 Chrome 状态)。具体而言,如果满足以下所有条件,Chrome 将不会执行通过 document.write()
注入的 <script>
元素:
- 用户的网络连接速度较慢,尤其是当用户使用 2G 网络时。(未来,此变更可能会扩展到网速较慢的其他用户,例如 3G 网速较慢或 Wi-Fi 网速较慢的用户。)
document.write()
位于顶级文档中。此干预措施不适用于 iframe 中的 document.written 脚本,因为它们不会阻止主页面呈现。document.write()
中的脚本会阻塞解析器。具有“async
”或“defer
”属性的脚本仍会执行。- 脚本未托管在同一网站上。换句话说,对于具有匹配 eTLD+1 的脚本(例如,在 js.example.org 上托管的脚本插入到 www.example.org 上),Chrome 不会进行干预。
- 脚本尚未存在于浏览器 HTTP 缓存中。缓存中的脚本不会产生网络延迟,并且仍会执行。
- 对该网页的请求不是重新加载。如果用户触发了重新加载,Chrome 不会干预,并会照常执行网页。
第三方代码段有时会使用 document.write()
加载脚本。幸运的是,大多数第三方都提供异步加载替代方案,可让第三方脚本加载,而不会阻止显示网页上的其余内容。
如何解决此问题?
简单的答案是,请勿使用 document.write()
注入脚本。我们维护着一组支持异步加载器的已知服务,建议您经常查看。
如果您的提供商不在列表中,但确实支持异步脚本加载,请告诉我们,以便我们更新此页面,为所有用户提供帮助。
如果您的提供商不支持将脚本异步加载到您的网页中,我们建议您与他们联系,并告知我们和他们,这将对他们产生怎样的影响。
如果您的提供商向您提供了包含 document.write()
的代码段,您或许可以向脚本元素添加 async
属性,或者使用 document.appendChild()
或 parentNode.insertBefore()
等 DOM API 添加脚本元素。
如何检测您的网站何时受到影响
有许多标准决定是否强制执行此限制,那么您如何知道自己是否受到影响?
检测用户使用 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 DevTools 中捕获警告
从 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 中仅在开发者控制台中显示警告。(Beta 版于 2016 年 7 月发布。我们预计将于 2016 年 9 月面向所有用户发布稳定版。)
我们将从 Chrome 54 开始(预计将于 2016 年 10 月中旬面向所有用户发布稳定版)干预,阻止为 2G 用户注入脚本。如需了解更多动态,请参阅 Chrome 状态条目。
随着时间的推移,我们希望在任何用户的连接速度缓慢(例如 3G 或 Wi-Fi 速度缓慢)时进行干预。请按照此Chrome 状态条目中的说明操作。
希望了解更多信息?
如需了解详情,请参阅以下其他资源: