<script>标签本身的加载和整体执行属于宏任务,它的执行过程可能包含同步任务和异步任务,会阻塞HTML解析和渲染,所以建议<script>写在</body>前。网页性能优化的手段还有<script>标签中的defer、async属性,用于控制脚本的异步加载和执行行为。
一、defer与async对比
defer | async | |
异步加载 | 不阻塞HTML解析,脚本在后台下载 | 不阻塞HTML解析,脚本在后台下载 |
执行时机 | HTML文档完全解析完成,DOM树构建完毕后,但在DOMContentLoaded事件之前执行,脚本在文档中的按照出现顺序执行 | 脚本一旦下载完成就立即执行(如果HTML解析已完成,则立即执行;如果HTML解析未完成,暂停解析,执行脚本,然后继续解析),多个async脚本的执行顺序取决于下载完成顺序 |
DOMContentLoaded | 在所有defer脚本执行完成后才会触发DOMContentLoaded事件 | 不等待async脚本执行完成就可能触发DOMContentLoaded事件 |
适用场景 | 有依赖关系或需要操作DOM的脚本 | 独立无依赖的脚本(如统计代码) |
二、注意事项
1.defer仅对外部脚本有效
<script defer>console.log('defer会被忽略');</script>
2.动态添加的脚本默认具有async行为
const script = document.createElement('script');
script.src = 'c.js';
document.body.appendChild(script);
3.模块脚本默认具有defer行为
<script type="module" src="xxx.js"></script>
4.兼容性
IE10+完全支持,更旧浏览器会忽略defer,退化为同步执行。