
本文详解浏览器中脚本执行与渲染的时序关系,阐明为何 requestAnimationFrame 可能早于 执行触发,并提供通过 blocking="render"、脚本位置控制及现代加载策略实现渲染阻塞的可靠方案。
本文详解浏览器中脚本执行与渲染的时序关系,阐明为何 `requestanimationframe` 可能早于 `<script>` 执行触发,并提供通过 `blocking="render"`、脚本位置控制及现代加载策略实现渲染阻塞的可靠方案。</script>
在构建高性能、无闪烁的 Web 应用时,一个常被忽视却至关重要的细节是:脚本执行与页面渲染的执行顺序并非绝对确定。尽管 JavaScript 是单线程的,但浏览器的渲染流程(包括样式计算、布局、绘制)与 JS 执行共享事件循环,而 requestAnimationFrame(RAF)回调被调度在「下一个帧的渲染前」——这恰恰发生在浏览器决定是否需要重绘的临界点。若脚本尚未执行完毕,DOM 状态可能未就绪,此时 RAF 触发便可能导致读取未挂载元素、样式未生效或 UI 闪动。
? 根本原因:Parser-blocking ≠ Render-blocking
-
Parser-blocking(解析阻塞):默认 <script>(尤其外部脚本)会暂停 HTML 解析器,确保 DOM 构建按序进行。例如:</script>
<script src="data:text/javascript,console.log(document.body.children.length);"></script><div>content</div>
此处 console.log 输出为 0,因为
尚未被解析——这是 parser-blocking 的典型表现。Render-blocking(渲染阻塞):但 parser-blocking 并不自动等同于 render-blocking。只有当脚本位于
中时,主流浏览器(Chrome、Safari)才会将其视为 render-blocking —— 即强制延迟首次渲染(paint),直到该脚本执行完毕。而放在 底部的脚本,虽阻塞解析,却不阻塞渲染队列,因此 RAF 可能抢在脚本执行前被调用。可通过 iframe 演示验证(规避 StackBlitz 环境限制):
<iframe srcdoc=" <html><head> <script>requestAnimationFrame(() => parent.postMessage(['RAF'], '*'));</script> <script>parent.postMessage(['SCRIPT EXECUTED'], '*');</script> </head><body><h1>HELLO</h1></body> </html>"> </iframe>在 Chrome 中,控制台稳定输出:
SCRIPT EXECUTED RAF
证明
内脚本实现了 render-blocking;若将第二个更多热门下载
更多相关下载
更多精品课程
相关推荐/热门推荐/最新课程
AngularJS教程共24课时 | 7.6万人学习
VBScript教程共10课时 | 10.4万人学习

