为何要避免使用 "document.write()"

本文是技术圈 google 浏览器前端新特性播报的推送,欢迎你们加入html

为何要避免使用 document.write()

最近咱们发现若是咱们在页面中使用了document.wirte(),那么在 chrome 的开发者控制台会出现下面的警告信息前端

(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.

为啥要作这个提示呢,对于在2G,3G 或者是慢 wifi 环境下面,使用document.write()动态加载资源会让页面的展示慢10秒以上,浏览器能够呈现页面以前,必须经过解析HTML标记来构建DOM树。每当解析器遇到脚本时,它必须中止并执行它,而后才能继续解析HTML。若是脚本动态地注入另外一个脚本,解析器将被迫等待更长时间才能下载资源,这可能会致使一个或多个网络往返并延迟首次渲染页面的时间,致使页面没法加载或花费的时间长于用户放弃。根据Chrome中的设备,咱们了解到,经过第三方脚本插入的document.write()页面的速度一般比2G的其余页面载入速度慢两倍。chrome

去除document.write的效果

chrome 开发者收集了28天chrome浏览器使用者的2G浏览数据,从中发现7.6%的2G加载页面中都包含了经过document.write()写入页面的跨网站,而且会中断浏览器解析的脚本。经过把这些加载脚本进行拦截加载,咱们看到了如下的改进:segmentfault

  • 页面加载到达first contentful paint(视觉上让用户感受正在加载的状态)t的状态的数量增长10%,达到彻底解析状态的页面数量增长25%,减小10%因为须要刷新页面带来的用户失望
  • 到达first contentful paint的时间减小了21%(加快速度大于1秒)
  • 解析页面所需的时间减小了38%,差很少加快了6秒,大大减小了向用户展现内容的时间

chrome 浏览器对于document.write的策略

针对以上的测试数据,chrome 从 55版本开始,chrome 浏览器对用户使用的document.write()进行干预,若是符合如下全部的状况,页面<script>标签中的document.write()将不会被执行:api

  1. 用户处于缓慢的链接状态,特别是用户在2G时。(未来可能会延伸到慢速链接的其余用户,例如慢速3G或慢速WiFi。)
  2. document.write()在一个顶级的文件中,不适用于iframe中的document.write脚本,由于它们不会阻止主页面的呈现。
    3.document.write()中加载的脚本是会阻断解析的,若是脚本中有async或者是defer属性,那么它们仍是会被解析执行

4.document.write()中加载的脚本和页面地址不是同个主域的,换句话说,chrome 浏览器不会阻止script标签符合eTLD+1规则的加载(好比页面地址是www.a.com,script的地址是 js.a.com
5.document.write()中加载的脚本还没有在浏览器HTTP缓存中。缓存中的脚本不会致使网络延迟,而且仍然会执行。浏览器

  1. 页面的请求不是从新加载。若是用户触发从新加载而且正常执行该页面,Chrome将不会进行干预。

如何检测你的document.write是否被执行限制了

chrome 提供了多种方式来检测你的document.write请求是否被限制了缓存

了解下你的用户在2G下面的使用占比

因为上面的规则现阶段只针对慢速状况2G,所以首先能够先分析出来,你的网站的2G 用户占比,经过chrome提供的网络信息 API,能够判断用户是否是在2G 环境下面,代码以下网络

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 devtools中,若是页面知足上面的2-5的规则,则会在chrome devtools中看到以下警告
clipboard.pngapp

异步

更加全面的告警

上面两种方式结合以后能够对影响的用户量有一个初步的判断,若是要作精确的判断,能够检查 HTTP 头部:
当插入的脚本document.write被阻止时,Chrome会将如下标头发送到所请求的资源:

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

当document.write发现插入脚本时,可能会在不一样状况下被阻止,Chrome可能会发送:

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

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

替换方案

因为document.write会减慢页面的加载,能够考虑使用appendChild等 api 将元素插入页面中,不过这二者有如下的区别

  • document.write的参数是一个 html 字符串,appendChild是一个Node对象
  • 若是有多个document.write写入 script 标签,标签与标签之间的加载是同步的,也就是说,标签的加载顺序会和document.write的执行顺序相同;而使用appendChild插入多个sciprt标签时,标签加载的顺序是不肯定的,先加载完成的先执行,所以经过appendChild插入script标签时,要注意是否须要对加载的顺序进行控制,能够经过script.onload进行顺序回调插入
相关文章
相关标签/搜索