history.back()后调用history.pushState不增加历史记录长度问题
现象说明
执行history.back()回退操作后,再调用history.pushState无法让history.length递增,现象截图如下:
可通过以下代码稳定复现:
history.pushState(null,null,"./abc"); history.back(); console.log(history.length); history.pushState(null,null,"./abc"); console.log(history.length);
该现象在Chrome、Firefox浏览器下均可稳定复现,属于标准定义的预期行为,并非浏览器实现bug。
核心原理
这个表现由History API的历史栈操作规则决定:
- 浏览器维护的历史记录栈由三部分组成:后退栈(已访问过、可回退的条目)、当前激活条目、前进栈(已回退、可前进到的条目),
history.length统计的是三部分的总条目数,回退、前进操作仅移动栈指针,不会删除条目,因此不会改变总长度。 - 当栈指针没有指向历史栈最后一个条目(即前进栈非空)时,调用
pushState会触发前进栈强制裁剪逻辑:浏览器会先清空前进栈内的所有条目,再在当前指针位置后插入新的历史条目。
逐步骤拆解复现逻辑
假设页面初始加载完成时,栈内只有1条初始页面记录,我们按代码执行顺序拆解栈的变化:
- 执行第一次
history.pushState(null,null,"./abc"):在当前条目后插入新记录,清空前进栈(此时前进栈本来为空),总条目数变为2,指针指向新插入的./abc条目。 - 执行
history.back():指针移回初始页面条目,之前插入的./abc条目被移入前进栈,总条目数仍然是2,因此第一次打印history.length结果为2。 - 执行第二次
history.pushState(null,null,"./abc"):首先清空前进栈(删掉了之前存的1条./abc记录),再在当前条目后插入新的./abc条目,总条目数还是2,因此第二次打印history.length结果和第一次完全一致,不会出现递增。
验证方式
你可以通过简单改动验证前进栈的存在:在history.back()执行后、第二次pushState前调用history.forward(),会发现页面无需刷新就能直接跳转到之前push的./abc路径,证明回退后该条目确实保存在前进栈中,没有被销毁。
注意:
history.back()是异步操作,如果你在调用back后立刻读取历史状态,可能拿到回退完成前的瞬时值,测试时可以将后续逻辑放在setTimeout回调中,或者监听popstate事件后再执行,避免结果偏差。
常见误区
- 不要把
history.length等同于当前浏览的路径深度,它只统计当前浏览上下文下存活的历史条目总数,和当前指针位置没有直接关系。 - 所有现代浏览器对这部分逻辑的实现都遵循WHATWG HTML标准,不存在跨浏览器的行为差异。
内容的提问来源于stack exchange,提问作者zhang olve
相关产品推荐
相关产品推荐

