请选择 进入手机版 | 继续访问电脑版
历史栈(History Stack),是指单个标签页(Tab)下打开新网址、点击超链接、执行 JavaScript 跳转等导航(Navigation)行为形成的历史记录序列。
由于浏览器支持前进后退,所以当前页面对应的历史记录并不总是位于历史栈栈顶。以下我们用 当前历史记录 来代指历史栈中处于激活状态的历史记录,示例中以 [X] 表示。

历史记录形成的条件

发起导航请求后并非立马就可以形成一条历史记录推入历史栈中。
新的历史记录的形成,以及前进后退时当前历史记录位置的变更 —— Chromium 统称为历史记录的提交(Commit)—— 均是以浏览器内核线程收到导航请求的主资源第一块数据为标准,在此之前,该导航请求处于 Pending 的状态。
  1. [/code]Pending 状态的导航请求随时可能会被新的导航请求中断。
  2. [code]
复制代码
也可以被用户点击浏览器“取消”按钮取消。
  1. [/code][size=5][b]历史栈的操作[/b][/size]
  2. 在导航行为发生时,浏览器会执行对该历史栈的增加、替换、淘汰等操作。
  3. [b]一、增加历史记录[/b]
  4. 增加历史记录通常发生在以下几种情况:
  5. [list=1]由地址栏等非网页界面打开新网址,参见NavigationControllerImpl::LoadURL点击超链接,参见 HTMLAnchorElement::HandleClick提交表单,参见 HTMLFormElement::ScheduleFormSubmissionJavaScript
  6. [/list]
  7. [list]Location.hrefLocation.assign()History.pushState()
  8. [/list]如果当前页面并不是在标签页中后退而来,也就是当前历史记录位于栈顶,则新增加的历史记录被推入栈顶成为当前历史记录。
  9. [code]
复制代码
否则,需要将历史栈中位于当前历史记录之后的记录全部清除,才能将新增加的历史记录推入栈顶成为当前历史记录。
  1. [/code][b]二、更新当前历史记录[/b]
  2. 更新当前历史记录通常发生在以下几种情况:
  3. [list=1]点击浏览器刷新按钮JavaScript
  4. [/list]
  5. [list]Location.reload()Location.replace()History.replaceState()
  6. [/list]更新当前历史记录只是修改当前历史记录的信息。
  7. [code]
复制代码
三、前进后退
前进后退通常发生在以下几种情况:
    点击浏览器的“前进”、“后退”按钮发起JavaScript

    History.back()History.forward()History.go()
前进后退只修改当前历史记录的位置,不更改历史栈中的历史记录。
  1. [/code][b]四、淘汰历史记录[/b]
  2. 淘汰历史记录通常发生在以下几种情况:
  3. [list=1]如前所述,历史记录增加时淘汰当前历史记录之后的全部记录。
  4. [/list][code]
复制代码
    历史记录数量超过了限制时,淘汰最早进入历史栈的记录,当前 Chromium 单个标签页最多支持 50 条记录。
  1. [/code][b]五、替换当前历史记录(进阶)[/b]
  2. 与“更新当前历史记录”只是基于当前历史记录更新信息不同,替换当前历史记录是删掉旧的历史记录,并创建新的历史记录代替,这么做的原因是旧的历史记录数据结构已经不能被复用,通常发生在 Cross-process location.replace navigation 。
  3. [code]
复制代码
子 Frame

子 Frame 加载的第一个页面不会生成新的历史记录,导航信息会被记录在对应的主 Frame 历史记录中。后续加载的页面形成一条新的历史记录的时候,会将主 Frame 的历史记录克隆并推入历史栈,其导航信息记录在克隆后的主 Frame 历史记录中。
[code][/code]常见问题

    Redirect
服务器端 302 跳转不影响未提交的历史记录,因为新导航请求的主资源第一块数据尚未收到;对于已提交的历史记录则会更新网址等信息。
    location.href vs location.replace
正常情况下,location.href 会生成一条新的历史记录,location.replace 会替换当前历史记录。但 location.href 并不必然导致一条新的历史记录的产生,在当前页面的 onload 事件发起之前,location.href 也是替换当前历史记录。
不过建议前端开发者不要据此实现空白页面跳转最终页面的逻辑,Chromium 当前对这种情况的处理属于兼容性操作,参见 NavigationScheduler::MustReplaceCurrentItem 。之前我们也遇到不少这种写法下依旧生成了新的历史记录的情况,导致后退一次,到了空白页面,又被 JavaScript 重定向到最终页面,必须快速连续后退两次才能退出这个死循环。
分享到 :
0 人收藏

5 个回复

倒序浏览
在下叶良辰  高级会员 | 2018-11-9 09:48:48
服务器端 302 跳转不影响未提交的历史记录,因为新导航请求的主资源第一块数据尚未收到;

302 时可以看到正在跳转的提升页面,应该收到第一块数据了,为什么不影响历史记录呢?

另外,微信应该把公众号的pushstate给禁掉,每次看文章回退到某几个页面,真特么烦。
爱是细水长流.  高级会员 | 2018-11-9 09:48:48
这里说的第一块数据是网络响应 Body 的数据,302 跳转是收到了网络响应的 Header 就重定向新的请求了。你说的已经看到了正在跳转的提示页面,是网页提示还是标题栏提示?前者肯定是 JavaScript 在做 location 重定向,不是 302 ;后者跟收到第一块数据没关系,收到 Header 就可以做到。
笑傲一生  中级会员 | 2018-11-9 09:48:48
不好意思,我记错了,那是 Meta 标签的跳转。
情深不寿  高级会员 | 2018-11-9 09:48:48
如果收到了第一块数据,就不是302 Redirect了
热情消退  中级会员 | 2018-11-9 09:48:48
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|翁笔

© 2001-2018 Wengbi.com

返回顶部