干预 document.write()  |  Web  |  Google Developers

426 阅读5分钟

译者:众里寻他千百度

原文链接

您最近是否在Chrome的开发者控制台中看到过如下警告,想知道这是什么吗?

(index):34 A Parser-blocking, cross-origin script, 
https://paul.kinlan.me/ad-inject.js, is invoked via document.write(). 
如果设备网络链接差,则可能会被浏览器阻止

可组合性是Web的一大优势,让我们轻而易举与第三方服务结合起来构建优质新产品! 组合的缺点是所有组成部分共同影响用户体验。 如果组合不是最佳的,用户体验将大受影响。

造成性能不佳的一个原因是在页面中使用document.write(),特别是那些使用注入脚本的。 像以下看起来无害,却可能会给用户带来真正的问题。

`document.write('`<script src=""https://paul.kinlan.me/ad-inject.js"">`</script>');`

浏览器要想呈现页面,必须通过解析HTML标记来构建DOM树。每当解析器遇到脚本时,它必须停止并执行该脚本才能继续解析HTML 。如果脚本动态地注入另一个脚本,则解析器被迫等待甚至去下载更长的资源,这可能招致一个或多个网络往返并延迟页面第一次渲染的时间。 对于网络连接缓慢的用户,如2G,通过document.write()动态注入的外部脚本 可以延迟主页内容显示数十秒,或导致页面无法加载或花费太长时间才放弃加载。 基于Chrome中的工具,我们了解到在2G网络中页面通过document.write()插入的第三方脚本通常比其他页面慢两倍。

我们从1%Chrome稳定用户收集28天实验数据,限制用户使用2G连接。 我们看到在2G上所有加载页面的7.6%至少包含一个跨站点的通过document.write()插入的阻塞解析的脚本。 通过阻塞这些脚本的加载,我们在这些负载上看到了以下改进:

  • 10% 更多页面加载到达 first contentful paint (用户可视化确认该页面正在有效加载),** 25%更多页面加载达到完全解析状态,并且 10%**重新加载意味着用户体验变好。

  • 平均时间减少21% first contentful paint

  • 解析网页的平均时间减少**38%**意味着提高了将近六秒,大大减少了展示用户需要数据的时间。 考虑到这些数据,Chrome从55版开始, intervenes 当检测到这个糟糕的模式,通过改变 document.write() 在Chrome中如何处理 (See Chrome Status)。 当满足下面 所有 条件,谷歌将不会执行 添加元素的 document.write() :

  1. 用户网络连接比较慢,尤其是2G. (未来,或许会扩展到其他慢的网络连接,比如 3G 或者比较慢的 WiFi.)

  2. document.write() 在顶级文档中。干预document.written脚本在iframes中不适用,因为他们不阻塞主页的渲染。

  3. document.write()中的脚本阻塞解析。使用asyncdefer属性的脚本仍被执行。

  4. 脚本不托管在同一个站点上。 换句话说,Chrome不会干预具有匹配eTLD +的脚本 (例如, 托管在js.example.org 插入到 www.example.org).

  5. 该脚本尚未在浏览器HTTP缓存中。 缓存中的脚本不会导致网络延迟,将会直接执行。

  6. 页面的请求不是重新加载。 如果用户触发重新载入,Chrome不会干预并正常执行页面。

第三方片段有时使用document.write()加载脚本。幸运的是,大多数第三方提供 异步加载选择,这会让第三方脚本在不阻塞页面其他内容展示的情况下加载。

##如何修复这个问题?

简单的答案就是不使用 document.write()插入脚本.我们在维护一组提供异步加载器支持的服务我们鼓励你继续检查。

如果您的程序不在列表中,并且支持异步脚本加载,那么请让我们知道,我们可以更新页面来帮助所有用户.

如果您的程序不支持异步加载脚本,我鼓励你去联系他们并让我们去尝试改进它。

如果你的脚本包含 document.write(), 你可以在script元素上添加async属性,或者通过 DOM API的document.appendChild()parentNode.insertBefore()方法添加script元素。像Google Analytics does那样。

##如何检测您的网站何时受到影响

有大量的标准决定了限制是否被执行,那么你怎么知道你是否受到影响?

检测2G用户

要了解这种变化的潜在影响,首先需要了解有多少用户使用2G。 您可以检测用户当前的网络类型,通过使用Network Information API加速 ,他在 Chrome 中给你的分析或者真实用户指标(RUM)系统发送一个预告。

if(navigator.connection &&
   navigator.connection.type === 'cellular' &&
   navigator.connection.downlinkMax <= 0.115) {
  //通知您的服务以表明您可能受此限制的影响。
}

###在Chrome DevTools中捕获警告 由于Chrome 53,DevTools对有问题的document.write()发出警告声明。 具体来说,如果document.write()请求符合条件2到5(Chrome在发送此警告时忽略连接条件),警告看起来像:

在Chrome DevTools中看到警告是非常好的,但是如何检测它呢?当干预发生时, 您可以检查发送到服务器的HTTP头信息。 **注意:**您可以在Chrome DevTools中启用“2G”模式,但是在Chrome 55中,它不正确触发干预。 最好的选择是通过chrome://flags/#disallow-doc-written-script-loads启用此干预。

**注意:**这种干预的启发之一是检测文件是否在用户的缓存中。 DevTools允许您禁用缓存,但是您不会看到onerror事件在脚本元素被触发,但是当您不使用DevTools时您将看到它。 这在Chrome 56已经修复。 ###检查脚本资源上的HTTP头

当通过document.write插入的脚本被阻塞时,Chrome会发送如下头部信息到所请求的资源:

`Intervention: <https://shorturl/relevant/spec>;`

当通过document.write插入的脚本被发现并被阻止时,不同的情况下,Chrome可能会发送:

`Intervention: <https://shorturl/relevant/spec>; level=""warning""`

干预头信息将作为脚本的GET请求的一部分发送(在实际干预的情况下异步)。

未来该何去何从?

初步计划是在满足检测标准时执行此干预措施。一开始在在Chrome 53 \的开发者控制台中只显示警告。(测试版在2016年7月\,我们预计稳定版将在2016年9月)。我们将在Chrome 54阻塞2G用户的插入脚本,估计2016年10月中旬发布稳定版本。检查 Chrome Status entry获取更多更新信息。

随着时间的推移,我么会阻塞所有网络缓慢的用户(i.e, 慢的3G 或 WiFi). 关注这里 Chrome Status entry.

##想了解更多?

要了解更多信息,请参阅以下附加资源:

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated May 16, 2017.