理解浏览器的历史记录

这是一篇基础文章,讲述一些浏览器里面历史记录栈管理的相关内容。写这个的原由,源于我最近想研究pushState,看看用它来实现SPA会遇到哪些问题,而pushState最终影响的就是浏览器历史记录栈里面的内容,因此就花了点时间琢磨了一下浏览器是如何管理历史记录栈的。由于在研究的过程当中,发现了一些曾经未曾注意到一些要点,因此就记录下来了。html

demo地址:http://liuyunzhuge.github.io/blog/history/demo1.htmlgit

这个demo用于进行本文后面内容涉及到的相关测试,假如你也感兴趣的话,建议每次要测试一个新的问题时,都在新选项卡里面打开这个demo,而不是从一个已经打开过网页的选项卡里面打开;由于已经打开过网页的选项卡,它的历史记录栈里面已经包含了以前访问的网页记录,因此会对你要测试的问题结果产生影响。github

浏览器会对同一个窗口(选项卡)中访问的网页进行记录,无论咱们是经过如下哪一种方式改变网页,浏览器都会把改变后的网页记录下来,以便经过浏览器的前进和后退按钮,可以快速的切换到已经访问过的网页:
1)直接在地址栏输入网页地址;
2)经过网页内的超连接点击,跳转到其它网页;可是不能是在新窗口中打开的连接;
3)经过脚本改变location.href跳转到其它网页;
4)经过表单提交跳转到其它网页;可是不能是提交到新窗口的表单。
总之,只要是在同一个窗口内,网页发生了跳转,浏览器都会记录。不过刷新除外,history对象的length属性能够查看当前窗口存储的历史记录总数,在前面的demo页面中,我把这个属性打印在页面上,只有网页改变的时候,这个属性才会变化;而刷新网页不会改变这个属性。chrome

浏览器有一个数据结构来存储网页的历史记录,我把它称之为历史记录栈,由于它的结构跟栈的使用方式有些类似。浏览器

操做测试一:假如你复制前面的demo地址,而后在chrome浏览器下按如下步骤进行操做:数据结构

打开新选项卡;输入demo1.html;点击demo2.html;点击demo3.html;点击demo4.html;点击demo3.html;点击demo2.html;点击demo1.html。测试

浏览器会如下图相似的方式来存储以上的访问记录:firefox

image

因为如今的浏览器都是多选项卡的模式,当你打开一个选项卡的时候,即便没有访问具体网页,浏览器也为这个选项卡建立好了BOM对象,好比history对象,而后把新选项卡的空白页做为历史记录里面的第一条记录。因此在上图中的最后一列能够看到8条记录,跟demo页面里显示的数字同样:3d

image

跟历史记录栈一块儿的,浏览器还有一个访问指针来表示当前网页在历史记录栈中的位置。默认状况下,当咱们经过前面列举的方式改变网页地址的时候,都会把新的页面压入到历史记录栈的顶部,同时把指针指向到这个最新的网页,就如上面的图中所示,每次改变了页面,当前页面的指针始终指向的是历史记录栈最顶部的那条记录;当咱们经过浏览器的前进后退功能(包括按钮,快捷,右键菜单等方式)或者是history提供的go/back/forward方法,都不会改变历史记录栈的内容,只会移动一下这个指针:指针

1)前进功能/go(1)/forward,只是让这个指针上移1个位置;

2)后退功能/go(-1)/forward,只是让这个指针下移1个位置;

3)go(n)让指针上移n个位置;go(-n)让指针下移n个位置。

浏览器根据移动后的指针位置,找到历史记录栈中的网页进行显示。假如接着操做测试一的结果,继续作如下操做。

操做测试二:点击7次浏览器后退按钮。

浏览器此时历史记录栈的存储状况就变成下面这个状态了:

image

虽然history.go(n)和history.go(-n)能够将指针移动到任意位置,可是当要移动到的位置超出了历史记录栈的位置范围时,指针就不会移动。因此在操做测试二的结果中,调用history.go(-100)和history.go(100)都是不会起做用的。

还有两种状况会改变历史记录栈的内容。

操做测试三:假如咱们接着操做测试二的结果,点击三次前进按钮,让浏览器的历史记录栈进入到下面这个状态:

image

此时因为操做测试二和操做测试三都没有改变历史记录栈的内容,因此正确的话,页面上的历史记录统计应该仍是8:

image

操做测试四:接着,咱们作如下两步操做:点击demo2.html,点击demo3.html。这个时候页面上的历史记录统计变成了:

image

history.length已经改变了,说明历史记录栈的内容也变化了。只不过为何变成6,而不是10(8+2)呢?看看此时浏览器历史记录栈的状态:

image

浏览器在往历史记录栈里面压入新的记录时,是直接在当前指针后面压入的,若是当前指针的后面,还有其它的记录项,都会被丢弃掉。这样就好理解为啥操做测试四以后的历史记录总数只有6个了。

浏览器对历史记录的管理还有一个要点就是对历史记录栈的存储总数有限制,chrome和firefox都是50。当历史记录栈的存储的量超出这个限制后,历史记录的存储就会采起滚动的方式存储,也就是新的记录会压入到栈的顶部,最底部的记录会从栈的底部移除出去。经过在demo页面里,不断地切换点击demo1,demo2,demo3,demo4,当达到必定次数的时候,页面打印的统计信息再也不变化,就表示达到历史记录达到限制了。不过IE11,我点到100多,发现它还在变化,说明IE的限制可能更高,也可能没有。。

本文记录了一些浏览器关于历史记录管理的内容,可能有分析不到位的地方,欢迎你们的批评与指正。以上内容但愿对有须要的朋友加深对history以及pushState的理解有所帮助,谢谢阅读:)


补充于2016-10-12:

网页锚点的变化,也会致使历史记录栈的更新,特性与前文描述相同。