本文为译文,原文地址:(clear current page UX)http://www.stevesouders.com/blog/2012/12/05/clear-current-page-ux/
昨天在 Perception of Speed 一文中我写了关于点击一个连接浏览器如何没有立即清除屏幕,而是清除前“等到下一个页面到来”。这提升了用户体验,用户可以浏览当前页面而不是空等待(看到一个空白的屏幕)。
那么,到底浏览器何时清除屏幕呢?可以选择下你认为最好的答案:
A.当页面第一个字节到达时
B.当新页面的body元素渲染时
C.当DOMContentLoaded触发时
D.当window.onload触发时
阅读全文
我早就猜到是“A”。事实上,多年来我一直告诉别人当前页面是在文档的第一个字节到达时清除的。当昨天我的同事 Ilya Grigorik 想知到底真浏览器何时清除页面时,这个看法改变了。事实证明答案是B,或者略在"B"之前——当新页面的body元素创建时。
测试页面
这里有一个测试页面来帮助大家探索这种行为:
这个页面包含里一段10秒才返回的脚本。(你可以改变URL中delay参数来控制延迟时间)。使用脚本的原因是它会阻塞浏览器解析HTML。把这段脚本放到页面的不同位置可以帮助我们隔离的判断屏幕何时被清除。脚本放置的三个位置选择:
1.head的顶部——script标签放置在head标签后面,title前面。这就当等同于新的文档的“首字节”。
2.head的底部——script标签放在</head>前面。当解析head的时候这里有些处理style块的工作。这可以让我们观察body标签创建前的状态。
3.body的顶部——script标签放在<body>标签后。这可以隔离出body元素创建后的状态。
背景被定义成随机的,这样可以清楚的判断body被渲染。
测试结果
我在主要的浏览器中运行了这3个测试,测量清除页面前各自等待的时间。我以为会是0或者10s,但是有些浏览器是在这之间。下面表格中统计出了各浏览器运行这3个测试用例的等待时间。
表格 1: 页面被清除前等待的秒时间 | |||
浏览器 | HEAD顶部 | HEAD底部 | BODY顶部 |
---|---|---|---|
Chrome 23 | ~5 | ~5 | 0 |
Firefox 17 | 10 | 10 | 0 |
IE 6-9 | 10 | 10 | 0 |
Opera 12 | ~4 | ~4 | ~4 |
Safari 6 | 10 | 10 | 0 |
让我们来分析下每个脚本位置情况下的结果,看看可以发现些什么。
#1:HEAD顶部
在这个测试中,10秒钟返回的脚本放在head和title之间:
<head> <script src=... <title>...
尽管html文档已经到达而且已经开始解析,没有一个浏览器在这个时候清除屏幕。所以,浏览器不会在第一个字节到达时清除页面。Firefox,IE,和Safari直到10s过后才清除屏幕,body标签已经被解析了(测试#3可以确认)。Chrome和Opera有非常有趣的行为——它们都在4-5秒之后清除屏幕。
主流浏览器在处理这个情况上有些各自的不同。哪一种更好——在新页面的body ready前保持老的页面,还是在几秒后清除老的页面?立即清除屏幕会给用户一些反馈,告诉用户过程正在进行中,但是也会留给用户一个空白的屏幕。(而且从昨天的假设来看,留下一个空白的屏幕是空闲的时间,这不太令人满意。)
Chrome和Opera会故意清除页面给用户反馈,还是通过其它方式来触发?ILya用chrome做了些深入的研究(deep dive tracing with Chrome),发现屏幕清除会配合GC回收。哪种行为更好并没有明确的答案,但是不同的浏览器在body解析后等待多久再清除屏幕会有差异,这非常有意思。
在这个测试中发现另一个有趣的事是title改变的时间。我惊奇的发现,所有浏览器会立即清除掉老的title,尽管老的页面的内容还没有改变。这就导致标题与页面的不匹配。除一个浏览器外,每个浏览器都用请求的URL替换掉老的title。这种方法有点笨重,因为URL在tab里没有足够的空间显示。Firefox是个例外,会在tab里显示“Connecting...”。这是一个非常有趣的主意,这个“临时”的标题显示了10秒,直到脚本下载完毕。这就说明脚本阻塞了title标签的解析。在下一个测试中可以看到script标签往下移之后title标题立马更新了。
#2:head底部
在这个测试中,10秒延迟的脚本放在head结束标签前面:
<script src=... </head> <body>
这个测试结果跟测试#1的结果是一样的。Firefox,IE,Safari 10秒,Chrome,Opera4-5秒。这个测试的主要点是确认浏览器不会在body标签解析前立即清除掉页面。
新页面的title会立即显示。因为title标签没有像测试#1中那样被脚本下载阻塞。这非常有趣,总之,浏览器解析title标签并更新标题,但是不会清除掉老页面的内容。这比前面的不比配更糟糕。在测试#1中临时的标题显示url或者“Connecting...”。现在新页面的真实标题现在了老页面的内容上面了。
#3:body顶部
在这个测试中10秒延迟的script标签放在body标签之后:
</head> <body> <script src=...
因为没有东西阻塞浏览器解析body标签了,除一个之外,其它浏览器都立即清除老的页面渲染新的body(通过随机的毕竟色来观察)。但是,因为下一个标签是10秒延时的脚本,阻止了页面的渲染,所以用户看到10秒钟的空白页面。Opera的行为不同——它在清除屏幕前保留了4s延迟。这非常的稀奇,它在等待啥?它解析了body标签而且在0时间时就知道新的页面有一个新的背景色,但是它等待了几秒钟才渲染。难道是脚本下载阻塞了渲染?但是脚本还有几秒才下载完,又是什么原因导致它回过头来渲染页面呢?
在这几个测试中,依我的观点,Opera做的最好。其它浏览器留给用户老的页面10秒钟,用户以为发生了什么问题呢(测试#1,#2 firefox,ie和Safari),或者留给用户一个空白页面10s钟当页面被阻塞渲染时(测试#3Chrome,Firefox,IE和Safari)。Opera始终折中让用户在清除页面前看3-4秒钟老的页面,然后剩下的6-7秒才显示空白页面或者新页面的body。
延伸
这些例子虽然有些认为故意的,但是会有些真实场景的延伸。
*浏览器通常在解析body标签后清除页面,而不是在第一个字节到达时。我说“通常”是因为在测试中可以通过在body前添加异步和内敛的脚本,但是这有点过分讲究。改变几行可能会改变行为,比如我不太确定浏览器会在何时清除掉页面。但是所有这些行为肯定是在页面的第一个字节到达之后。
*没有明确的最好的清除页面体验。主流浏览器有相当不同的行为,而且不确定这些差异是不是有意的。从一个页面切换到另一个页面每天都有数十亿次。我很惊讶,没有更多一致的数据来产生最好的用户体验。
*避免前端SPOF(single point of failure)。我已经写了广泛的内容关于为何加载同步的脚本会在页面中创建单点故障(Frontend SPOF)。这部分新的信息页面何时被清除添加到了slow-loading同步脚本,尤其是浏览器处理的不同方式。不管如何,尽可能的使用异步脚本加载(Loading Scripts Without Blocking)。