页面运行时状态

页面运行时状态指当前文档对应的 JS 内存、DOM 树和临时 UI 现场;整页导航或刷新时它通常会被销毁。

#type / concept #status / growing #tech / dev / frontend #platform / browser #resource / web

[!info] related notes

页面运行时状态

页面运行时状态指的是:当前文档这一次运行过程中,实际活在页面环境里的那份状态现场。

一句话定义

它主要包括当前页面的 JS 堆内存、组件树状态、DOM 树状态以及各种尚未持久化的临时 UI 状态。

为什么这个概念重要

很多人说“整页跳转会丢状态”,真正容易丢的通常不是 sessionStorage 或数据库里的数据,而是这份只存在于当前页面运行现场里的状态。

它通常包含什么

JS 内存状态

  • React / Vue 组件 state
  • 全局 store 里的内存数据
  • 普通变量、闭包里的中间值
  • 已请求回来但尚未持久化的数据缓存

DOM 状态

  • 输入框里尚未提交的内容
  • 当前滚动位置
  • 节点展开 / 折叠状态
  • 焦点位置
  • 动画中间态

临时 UI 状态

  • 当前打开了哪个弹窗
  • 当前选中了哪个 tab
  • 当前列表展开到哪一层
  • 当前页面是否处于某个加载中的过渡状态

它不等于什么

不等于 Web Storage

  • sessionStorage
  • localStorage

这些属于浏览器提供的持久化或半持久化存储,不等于当前页面运行现场本身。见 浏览器客户端存储

不等于服务端状态

  • 用户资料
  • 已保存草稿
  • 服务端购物车
  • 数据库记录

这些状态不随着当前页面 JS 上下文销毁而一起消失。

为什么整页跳转或刷新时它会丢

传统整页导航时,浏览器通常会:

  1. 卸载当前文档
  2. 销毁当前页面对应的 JS 执行环境
  3. 销毁旧 DOM 树
  4. 加载新的 HTML
  5. 创建新的页面环境

所以只要状态没有被同步到 URL、Storage、服务端或其他持久层,它就会随着旧页面一起消失。

sessionStorage 最容易混淆的点

sessionStorage 通常在同一个 tab 的会话期内还能保留,但页面运行时状态不会自动写进去。

也就是说:

  • sessionStorage 能保住“一个值”
  • 但它保不住“当前页面已经运行到哪一步”

例如它可以保住:

  • draft = "hello"

但它保不住:

  • 某个 Promise 正执行到哪
  • 某个组件树当前已经挂载到什么状态
  • 某个动画中间帧
  • 某些闭包现场

为什么 SPA 更容易保住它

SPA 路由切换时,通常不会销毁整个文档和 JS 运行环境,而是:

  • 更新 URL
  • 切换部分组件
  • 复用全局 store、缓存和布局

所以很多状态仍然活在同一个应用运行时里。

但这不代表 SPA 天然不会丢状态。只要用户刷新页面,或状态只存在某个已卸载组件里,它仍然可能丢失。

前进后退是一个特例

如果浏览器命中 BFCache 页面级缓存,前进后退有时会直接恢复整个页面快照,而不是重新初始化页面。

这时用户会感觉“状态没丢”,因为浏览器恢复的正是之前那份页面运行现场。

最短记忆方式

页面运行时状态 = 当前页面这一次运行里活着的 JS 内存 + DOM 状态 + 临时 UI 现场。

创建于 2026/4/23 更新于 2026/5/27