Flask render_template中JavaScript加载顺序疑问
关于带
type="module"的JavaScript脚本加载执行顺序规则解析 核心原因是模块脚本(type="module")和普通脚本的加载执行逻辑完全不同,这直接导致了你看到的输出顺序不符合预期。以下是具体规则和对你代码的分析:
1. 普通脚本(无type="module")的执行逻辑
- 内联普通脚本:浏览器解析到它时会立即执行,阻塞后续HTML解析,直到脚本执行完毕。
- 外部普通脚本:默认会先下载脚本文件,下载完成后立即执行,同样阻塞HTML解析(可通过
async/defer修改行为,但你代码中的内联脚本未使用这些属性)。
2. 模块脚本(type="module")的核心特性
- 自动延迟执行:无论模块脚本放在
<head>还是<body>,浏览器都会先完成整个HTML的解析,再执行模块脚本——这是模块脚本的默认行为,等价于给普通脚本添加defer属性。 - 异步加载:模块脚本的下载过程是异步的,不会阻塞HTML解析,下载完成后会等待HTML解析完毕再执行。
- 顺序执行:所有模块脚本会按照它们在HTML文档中出现的先后顺序执行(如果有导入依赖,会先加载依赖再执行当前模块)。
结合你的代码的执行流程
- 浏览器解析HTML,遇到
<head>里的<script type="module" src="scripts.js">,开始异步下载该脚本,但不阻塞HTML解析。 - 继续解析到
<body>内的<script>console.log('start base 1html')</script>,立即执行,控制台输出start base 1html。 - 继续解析HTML内容(包括加载navbar、sidebar等模板片段),随后遇到
<script>console.log('start base2 html')</script>,立即执行,控制台输出start base2 html。 - 整个HTML解析完成后,浏览器按顺序执行之前下载好的模块脚本:先执行
<head>中的scripts.js,再执行<body>末尾的script_body.js。
因此你实际看到的控制台输出顺序应该是:
start base 1html start base2 html [scripts.js中的console.log内容] [script_body.js中的console.log内容]
调整执行顺序的可选方案
如果需要让模块脚本在普通脚本之前执行,有两种方式:
- 移除模块脚本的
type="module"属性,将其改为普通脚本(但会丢失模块的import/export等特性)。 - 给普通内联脚本添加
type="module"属性,让所有脚本都延迟到HTML解析完成后按文档顺序执行,此时输出顺序会变为:scripts.js→start base 1html→start base2 html→script_body.js。
内容的提问来源于stack exchange,提问作者runRyan
相关产品推荐
相关产品推荐

