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"
相关推荐
雁鸣零落12 分钟前
如何在 Chrome 中查看其他浏览器的书签?书签空间订阅与侧边栏只读切换指南
前端·chrome·edge浏览器
hpoenixf43 分钟前
一天上线 + 零返工:我如何给复杂前端需求建立“安全感”
前端
广州华水科技1 小时前
单北斗GNSS变形监测系统在水利工程安全保障中的应用与优势分析
前端
yqcoder2 小时前
CSS 外边距重叠(Margin Collapsing):现象、原理与完美解决方案
前端·css
山楂树の2 小时前
图像标注大坑:img图片 + Canvas 叠加标注,同步放大后标注位置偏移、对不齐?详解修复方案及亚像素处理原理
前端·css·学习·canva可画
本山德彪2 小时前
我做了一个拼豆图纸生成器,把照片秒变图纸
前端
DTrader3 小时前
用TS无法实盘量化? - 实盘均线策略
前端·api
进击的夸父3 小时前
vfojs:Vue 超集架构,外壳React灵魂Vue
前端
编程老船长3 小时前
解决不同项目需要不同 Node.js 版本的问题
前端·vue.js
Wect3 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·算法·typescript