document.readyState 的三个有效取值是 loading、interactive、complete;其中 interactive 是 DOM 构建完成且 document.body 必然可访问的关键状态,适合白屏优化,需组合检查、事件监听与超时兜底来安全响应。

document.readyState 的三个有效取值分别是 loading、interactive、complete
现代浏览器中稳定可用的只有这三个值,uninitialized 和 loaded 属于历史遗留或已弃用状态,实际项目中不应依赖。
它们不是时间点,而是 HTML 解析流程中的关键断点:
-
loading:HTML 文档正在解析中;此时document.body很可能还不存在,同步脚本执行时大概率处于该状态 -
interactive:DOM 构建完成(等价于DOMContentLoaded已触发),document.body必然可访问,但图片、样式表、异步脚本等子资源仍在加载 -
complete:所有资源(含img、iframe、字体、第三方 tracker)全部加载完毕;等同于window.onload触发时机,通常比interactive晚数秒甚至更久
为什么 interactive 是最值得盯住的状态
白屏优化的核心是「尽早操作 DOM」,而不是等页面“彻底就绪”。
interactive 是唯一同时满足以下条件的状态:
立即学习“前端免费学习笔记(深入)”;
- HTML 解析结束,
document.body100% 存在且可写 - 不等待图片、CSS、第三方脚本等易阻塞资源
- 不会像
DOMContentLoaded那样在<head>内联脚本中因 DOM 尚未解析到<body>而报Cannot read property 'appendChild' of null - 是浏览器同步暴露的属性,无需事件监听即可立即读取
如何安全地响应 interactive 状态
不能只靠一次判断,也不能只绑事件监听——要组合使用、带兜底。
推荐做法:
- 立即检查
document.readyState:若已是interactive或complete,直接执行初始化逻辑 - 否则监听
document.onreadystatechange,并在回调中用if (document.readyState === 'interactive')判断,匹配后立刻removeEventListener或置空 handler,防止重复执行 - 加一个 5s 超时定时器(
setTimeout),超时后强制执行初始化(避免极端解析卡死或事件丢失) - 即便进入
interactive,仍建议包裹if (document.body)判断——极少数 iframe 场景或某些 polyfill 下,document.body可能短暂为null
常见误用和坑点
很多脚本失败,不是因为逻辑错,而是对状态理解偏差或边界没兜住。
- 把
document.readyState === 'complete'当作 DOM 可操作前提:会导致白屏时间拉长,尤其在首屏有大量图片或第三方资源时 - 仅监听
readystatechange却不检查当前状态:若脚本晚于 HTML 解析完成才加载,事件早已触发过,监听会漏掉 - 用
document.addEventListener('DOMContentLoaded', ...)替代interactive判断:虽然多数情况等效,但DOMContentLoaded不保证document.body已挂载(例如脚本在<head>中且 DOM 还没解析到<body>) - 忽略跨 iframe 场景:在 iframe 中读取父文档的
readyState可能受限于同源策略,返回值不可靠
真正关键的不是“知道有三个值”,而是理解 interactive 所代表的那个精确窗口:DOM 就绪、主线程未被阻塞、资源加载尚未拖累用户体验——这个时机稍纵即逝,得抓准,也得兜住。



















