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"
相关推荐
m0_471199632 小时前
【vue】dep.notify() 是什么意思?
前端·javascript·vue.js
威风的虫2 小时前
Vue3中的生命周期钩子函数
前端·javascript·vue.js
m0_471199632 小时前
【vue】vue2和vue3响应式原理区别
前端·javascript·vue.js
拜无忧2 小时前
纯css,顺时针3d旋转基座(摩天轮效应)
前端·css
奋斗猿3 小时前
从0到1开发跨平台桌面应用:Electron 实战全指南
前端·electron
之恒君3 小时前
script 标签中的 async 和 defer 的区别
前端·javascript
lkbhua莱克瓦243 小时前
项目知识——Next.js App Router体系
开发语言·javascript·项目知识
浪浪山_大橙子3 小时前
使用Electron+Vue3开发Qwen3 2B桌面应用:从想法到实现的完整指南
前端·人工智能
狗哥哥3 小时前
聊聊设计模式在 Vue 3 业务开发中的落地——从一次代码重构说起
前端·架构