
当通过 document.write 等方式在脚本执行过程中动态插入无 src 的普通(非模块) 标签时,浏览器会立即同步执行该新脚本,即使已有脚本正在运行——这是 WHATWG 规范中明确规定的“中断式执行”行为。
当通过 `document.write` 等方式在脚本执行过程中动态插入无 `src` 的普通(非模块)`<script>` 标签时,浏览器会**立即同步执行该新脚本**,即使已有脚本正在运行——这是 whatwg 规范中明确规定的“中断式执行”行为。</script>
在 HTML 解析与执行模型中,“脚本中断另一脚本”的现象并非源于多线程抢占或异步调度,而是由HTML 解析器的同步重入机制所导致。其核心触发条件严格限定为以下三点同时满足:
- ✅ 脚本为 经典脚本(non-module):即未声明
type="module"; - ✅ 无
src属性:即为内联脚本(inline script),内容直接写在标签体内; - ✅ 在已有脚本执行期间被动态注入:典型场景是
document.write()、document.writeln()或document.open()/close()配合写入,导致解析器重新进入“tokenization → tree construction”流程,并即时触发新<script></script>的准备与执行。
? 典型复现示例
<script>
console.log("Step 1: outer script starts");
document.write(`
<script>
console.log("Step 2: nested script runs IMMEDIATELY");
// 此处执行时,外层脚本的后续语句尚未运行!
<\/script>
`);
console.log("Step 3: outer script resumes — but only AFTER nested script finishes");
</script>✅ 控制台输出顺序为:
Step 1: outer script starts Step 2: nested script runs IMMEDIATELY Step 3: outer script resumes — but only AFTER nested script finishes
这印证了规范中所述的 “immediately execute the script element el, even if other scripts are already executing” —— 新脚本不是排队等待,而是同步插入执行栈顶端,形成调用栈嵌套。
⚠️ 关键注意事项
- ❌
async/defer属性对此类动态插入的内联脚本完全无效:它们仅作用于具有src的外部脚本; - ❌
type="module"脚本不触发此行为:模块脚本始终延迟到 HTML 解析完成(DOMContentLoaded 前),且遵循严格的依赖拓扑,不会被document.write中断; - ⚠️
document.write在页面加载完成后调用将清空整个文档,因此该机制仅存在于初始解析阶段(loading状态),现代开发中应避免使用; - ? 此行为属于遗留兼容机制,已被 HTML5 明确标记为“不推荐”,并在
document.currentScript等 API 设计中体现其不可靠性(例如currentScript在document.write插入的脚本中可能为null)。
✅ 替代方案(现代实践)
如需动态执行代码,请优先采用安全、可控的方式:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
立即学习“前端免费学习笔记(深入)”;
// ✅ 推荐:创建 script 元素并显式 append 到 head/body
const script = document.createElement('script');
script.textContent = 'console.log("dynamically injected");';
document.head.appendChild(script);
// ✅ 更佳:使用 import() 动态导入模块(支持 Promise、错误捕获)
import('./utils.js').then(module => module.init());这类方式由 JS 引擎控制执行时机,不干扰 HTML 解析器状态,规避了中断执行带来的不可预测性(如 document.write 导致的解析阻塞、布局抖动、SEO 损害等)。
总之,理解这一机制不仅关乎规范细节,更是识别和规避老旧代码风险的关键——它提醒我们:HTML 解析器与 JS 执行引擎的耦合远比表面更深层,而“同步中断”正是这种耦合最典型的副作用。


















