script 标签的异步加载:async、defer、type="module" 详解

script 标签的异步加载:async、defer、type="module" 全面解析

本文主要是分享一下,关于加载script多种方式及区别

  • 1.同步加载:<script src="index.js"></script>
  • 2.defer 异步加载:<script defer src="index.js"></script>
  • 3.async 异步加载:<script async src="index.js"></script>
  • 4.module 异步加载:<script type="module" src="index.js"></script>
  • 5.module async 异步加载:<script type="module" src="index.js" async></script>

众农周知,浏览器解析html时,如果遇到使用 <script src="index.js"></script> 加载js时,html的解析会被阻塞,这个时候会先去下载index.js,等待下载完并执行完js之后,然后再继续解析html。这样的话,如果js下载时间过长,无疑会增加页面的渲染时间,那么,有没有啥办法可以让解析html与下载js并行执行呢?有的,并且提供了多种。

1.五种加载方式深度解析

1.1 同步加载 <script src="index.js"></script>

特点
  • 阻塞解析html
  • 须等加载完js并执行完之后才能继续解析html
  • 增加首屏渲染时间

不推荐使用

适用场景
  1. 传统的加载script方式,需要兼容低版本浏览器
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!-- 同步加载且阻塞解析html -->
   <script src="index.js"></script>
  </head>
  <body>
  </body>
</html>

1.2 异步加载,使用 defer属性

特点
  • 并行下载js
  • 不阻塞解析html,解析html与下载并行
  • 在html解析完成DOMContentLoaded事件触发执行
  • 多个script时,异步加载,按顺序执行
适用场景
  1. 加载的js存在依赖关系,须按顺序执行
  2. 加载的js需要操作DOM
  3. 常见vue、react项目中,构建工具已自动处理,编译后自动添加defer属性
html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" href="/test/favicon.ico" />
    <title>xxxxx管理系统</title>
    
    <!-- 异步加载,优先执行第三方依赖 -->
    <script defer="defer" src="/test/js/chunk-vendors.0821bbb1.js"></script>
    <!-- 异步加载,上面的js执行完再执行 -->
    <script defer="defer" src="/test/js/app.566a7ad5.js"></script>
    
    <link href="/test/css/chunk-vendors.ff7db5f3.css" rel="stylesheet" />
    <link href="/test/css/app.0d1bd94e.css" rel="stylesheet" />
  </head>

  <body>
    <noscript
      ><strong
        >System doesn't work properly without JavaScript enabled. Please enable
        it to continue.</strong
      ></noscript
    >
    <div id="app"></div>
  </body>
</html>

1.3 异步加载,使用 async属性

特点
  • 并行下载js
  • 下载阶段,不阻塞解析html,解析html与下载并行
  • 下载完成后马上执行
  • 多个script时,异步加载,谁先下载完谁就执行
  • 可能阻塞解析html,如果解析html完成前就已经下载完了,那就会执行js,阻塞解析html
  • 可能会阻塞 DOMContentLoaded 事件的触发时机 当js在 DOMContentLoaded 事件触发前完成下载并执行,就会延长 DOMContentLoaded的触发时间,js的执行会阻塞主线程,执行完才会触发 DOMContentLoaded事件
适用场景
  1. 加载的js没有赖关系,单独执行
  2. 加载的js无需操作DOM
  3. 常用于分析、广告、埋点脚本加载
html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" href="/test/favicon.ico" />
    <title>xxxxxx官网</title>
    
    <!-- 异步加载,独立运行,无脚本依赖 -->
    <script async src="https://www.guanggao.com/gg/js?id=GG_1"></script>
    <script async src="https://www.guanggao.com/gg/js?id=GG_2"></script>
  </head>

  <body>
    <noscript
      ><strong
        >System doesn't work properly without JavaScript enabled. Please enable
        it to continue.</strong
      ></noscript
    >
    <div id="app"></div>
  </body>
</html>

1.4 异步加载,使用 type="module"属性

特点与defer差不多
  • 不阻塞解析html,解析html与下载并行
  • 在html解析完成DOMContentLoaded事件触发执行
  • 多个script时,异步加载,按顺序执行
  • defer主要差异是,使用esm模块化,且默认开启严格模式
适用场景 与defer差不多
  1. 加载的js存在依赖关系,须按顺序执行
  2. 加载的js需要操作DOM
  3. 使用esm开发的脚本
  4. 常见使用vite构建的vue、react项目中,编译后自动添加type="module"属性
html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" href="/test/favicon.ico" />
    <title>xxxxxx系统</title>
    
    <!-- 异步加载,使用esm开发 -->
    <script type="module" crossorigin src="/assets/index-BmxZ5FsG.js"></script>
  </head>

  <body>
    <noscript
      ><strong
        >System doesn't work properly without JavaScript enabled. Please enable
        it to continue.</strong
      ></noscript
    >
    <div id="app"></div>
  </body>
</html>

1.5 异步加载,使用 type="module" async属性

特点与async差不多
  • 并行下载js
  • 下载阶段,不阻塞解析html,解析html与下载并行
  • 下载完成后马上执行
  • 多个script时,异步加载,谁先下载完谁就执行
  • 可能阻塞解析html,如果解析html完成前就已经下载完了,那就会执行js,阻塞解析html
  • 可能会阻塞 DOMContentLoaded 事件的触发时机 当js在 DOMContentLoaded 事件触发前完成下载并执行,就会延长 DOMContentLoaded的触发时间,js的执行会阻塞主线程,执行完才会触发 DOMContentLoaded事件
  • async主要差异是,使用esm模块化,且默认开启严格模式``
适用场景 与async差不多
  1. 加载的js没有赖关系,单独执行
  2. 加载的js无需操作DOM
  3. 常用于分析、广告、埋点脚本加载
html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" href="/test/favicon.ico" />
    <title>xxxxxx官网</title>
    
    <!-- 异步加载,使用esm开发,独立运行,无脚本依赖 -->
    <script type="module" async src="https://www.guanggao.com/gg/js?id=GG_1"></script>
  </head>

  <body>
    <noscript
      ><strong
        >System doesn't work properly without JavaScript enabled. Please enable
        it to continue.</strong
      ></noscript
    >
    <div id="app"></div>
  </body>
</html>

2.总结

2.1.加载script的5种方式:

  • 同步-阻塞解析html: <script>
  • 异步-不阻塞解析html-按顺序执行: <script defer>
  • 异步-不阻塞解析html-无序下载完立即执行: <script async>
  • 异步-esm-不阻塞解析html-按顺序执行: <script type="module">
  • 异步-esm-不阻塞解析html-无序下载完立即执行: <script type="module" async>

2.2.各方式差异:

加载方式 执行时机 是否阻塞HTML解析 执行顺序 适用场景
<script> 立即执行 文档顺序 传统脚本
<script defer> DOM解析后 文档顺序 依赖DOM的脚本
<script async> 下载完成后 下载不阻塞,执行可能阻塞 无序 独立第三方脚本
<script type="module"> DOM解析后 文档顺序 ES模块化代码
<script type="module" async> 下载完成后 下载不阻塞,执行可能阻塞 无序 独立ES模块

2.3.加载流程图:

2.4.使用建议:

  • js使用非esm,优先考虑使用 defer
  • js使用esm,优先考虑使用 type="module"
相关推荐
恋猫de小郭35 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端