type属性本身不触发预解析阻塞,但非javascript类型会直接让浏览器跳过该script标签的下载与执行;type="text/javascript"或省略type时,预解析器会立即启动外链脚本的预加载,而内联脚本无论type为何均不参与预解析。

type 属性本身不触发预解析阻塞,但非 JavaScript 类型会直接让浏览器跳过该 <script></script> 标签的下载与执行——它根本不会进入预解析流程。
type="text/javascript" 或省略 type 时,预解析器如何处理
现代浏览器(Chrome、Firefox、Safari)在 HTML 预解析阶段遇到 <script></script> 且 type 为 text/javascript、application/javascript 或未声明时,会立即启动脚本资源的预加载(preload),即使它还没被主解析器真正“解析到”。
常见错误现象:
- 你在
写了<script src="a.js"></script>,DevTools Network 面板却看到a.js在后半段才开始请求 —— 很可能是因为它被标记为type="module"或其他非默认类型,预解析器直接忽略 - 使用构建工具(如 Vite/Vue CLI)注入的内联初始化脚本没被预加载,导致首屏 JS 执行延迟
实操建议:
- 外链脚本若依赖快速加载(如性能监控 SDK),务必确保
type是默认值或显式设为text/javascript;不要写成type="text/ecmascript"等冷门 MIME 类型 - 预解析只对带
src的外链脚本生效;内联脚本(无src)无论type是什么,都不会被预加载 - 可通过 Chrome DevTools → Rendering → “Paint flashing” + Network 面板时间轴,对比有无
type声明时的资源发现(discovery)时间差
type="module" 会改变预解析行为吗
会。虽然 type="module" 脚本默认具有 defer 行为,但它在预解析阶段的处理逻辑和普通脚本不同:浏览器会提前发起模块图(module graph)的静态分析,包括识别 import 语句并预加载所有依赖模块。
使用场景:
- 你用
import { foo } from './utils.js',即使utils.js在 DOM 中尚未出现,预解析器也会尝试提前获取它 - 多个
type="module"脚本之间存在 import 依赖时,预解析器会按图拓扑排序,而非 HTML 文档顺序
容易踩的坑:
-
type="module"不支持document.write(),预解析阶段若遇到含该调用的模块,会直接报错并中断整个模块图加载 - 动态
import()不参与预解析,只在运行时触发加载 —— 别指望它被提前发现 - 如果模块路径是拼接字符串(如
import('./' + name + '.js')),预解析器无法静态分析,也就不会预加载
type="text/html" 或其他非 JS 类型完全不参与预解析
当 type 是 text/html、application/json、text/template 等非可执行 JS 类型时,浏览器预解析器会直接跳过该 <script></script> 标签:既不下载其 src,也不解析内容,更不会将其加入执行队列。
这其实是种常用技巧:
- 把模板字符串放在
<script type="text/html">{{name}}</script>里,能避免被当作 JS 执行,又方便 JS 用innerHTML读取 - 某些 CMS 输出的内联配置数据也用
type="application/json"包裹,确保安全且不干扰 JS 执行流
注意点:
- 这种写法对预解析“零影响”,但如果你误以为它会被缓存或预加载,就可能在需要时才发现资源根本没发请求
- 不要给这类脚本加
async或defer—— 浏览器会忽略这些属性,因为它们只对可执行脚本有意义 - 服务端渲染(SSR)中若把初始状态塞进
type="application/json",记得前端 JS 主动读取,别指望它自动注入全局变量
预解析不是黑盒,但它只认标准 JS MIME 类型;一旦 type 偏离 text/javascript 或其等价形式,浏览器就当它不存在——这个边界比很多人想的更硬、更早。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











