文章目录
- 同步加载和异步加载
- JS模块的加载方法
- CommonJS
- ES6
- ES6的`<script>`标签的加载方式
同步加载和异步加载
- 同步加载:同步加载是指在主线程上按
顺序执行代码
,当遇到加载资源(例如网络请求、读取文件)时,主线程会停止
执行后续的代码,等待资源加载完成后再接着执行后续的代码。这样的方式可能会导致用户体验不佳,因为当资源加载耗时长时,用户需要等待较长时间才能看到后续的处理结果。 - 异步加载:异步加载则
不会阻塞主线程
,它会在后台加载资源
,同时主线程还会继续执行后续的代码。当资源加载完成后,通常通过回调函数
或者Promise
(.then方法)来获取资源,并对其进行处理。这样的方式可以避免阻塞主线程,提升用户体验。
异步加载就是多个资源同时加载,同步加载就是同一时刻只加载一个资源。
JavaScript中,由于它的单线程特性,通常推荐使用异步加载的方式来处理网络请求、文件操作等耗时操作。
JS模块的加载方法
CommonJS
使用CommonJS规范require()
函数加载模块是同步
的,也就是说在加载完模块之前,后续代码不会执行。这在服务器端环境中非常有用,因为模块文件通常都已经在本地,加载很快,而且一般需要在服务器启动时加载所有必要的模块。
ES6
ES6的模块既可以使用同步加载也可以使用异步加载,取决import的使用方式:
-
同步加载:同步加载是使用import的静态导入方式,结合from使用 :
静态加载没有返回值,静态加载是一个语句,import module from 'module-name';
在module模块加载完成之前是不会执行下面的代码的,所以在模块导入后的所有地方都可以直接使用该模块。
-
异步加载:异步加载是使用import的动态导入方式,模块作为import的参数使用(可以是路径名也可以是模块名):
动态加载的返回值是一个Promise对象
,所以可以直接使用.then
函数编写回调函数import('module-name').then((module) => { // 你可以在这里使用模块 });
也可以使用async/await语法,
async function loadModule() { try { const module = await import('module-name'); // 使用这个模块 } catch (error) { // 处理加载错误 } }
ES6的<script>
标签的加载方式
-
<script >
导入 —— 同步加载
<script src="">
标签并不是使用模块化的导入导出方式,可以使用该标签加载执行JS文件,但是其中所有的变量和函数都会在全局作用域中。
<script src="">
的导入方式是同步导入。当解析到<script src=“”>
的时候会暂停解析HTML,去下载javascript文件,等文件下载完成之后再继续解析剩余的HTML文件。 -
<scrtpt type="module">
导入 —— 异步加载
使用这种方式导入的文件是异步导入,使用<scrtpt type="module">
导入的时候浏览器会采用严格模式,并且模块会自动地被异步加载
<script type="module"> import {foo} from './foo.js'; foo(); </script>
或者使用src导入文件:
<script type="module" src="./main.js"></script>
main.js
import {foo} from './foo.js'; foo();
-
<script src=“”>
的异步加载
可以在<script>
标签中添加async
和defer
属性来使文件异步加载。-
async 属性:这会使得浏览器非阻塞(异步)地下载 JavaScript 文件,
但是一旦文件下载完成,浏览器会立刻解析并执行这个文件
,这导致了 HTML 的解析可能会被暂时阻塞。多个包含 async 属性的<script>
标签,它们的执行顺序无法保证,完全由加载完成的时间顺序决定。 -
defer 属性:这也会使得浏览器非阻塞(异步)地下载 JavaScript 文件,但是与 async 不同的是,包含 defer 属性的
<script>
标签会在整个 HTML 文档解析完成之后才开始执行
。如果有多个包含 defer 属性的<script>
标签,它们的执行顺序会按照在 HTML 文件中的出现顺序来执行。
-
-
<script>
标签异步引入的时候如何判断模块加载完成
使用<script src="">
标签的异步引入,不像直接在js
模块中的异步引入可以使用回调函数和Promise来编写异步模块加载完成之后的逻辑,但是我们有其他的解决办法:-
使用事件监听器
<script> document.querySelector('script[src="script.js"]').addEventListener('load', function() { // script.js文件加载完成之后执行的逻辑代码 }); </script> <script async src="script.js"></script>
-
使用
onload
事件监听<script type="module" src="./main.js" onload="init()"></script> <script> function init() { // main.js 已加载完毕,你可以在这里使用它导出的函数和变量 } </script>
-
如果被异步加载的文件可以手动编写,可以使用设置全局回调函数的方式:
<script> window.scriptLoaded = function() { // script.js文件加载完成之后执行的逻辑代码 }; </script> <script async src="script.js"></script>
然后在 script.js 中的最后一行调用 scriptLoaded 函数:
// script.js文件的逻辑代码 window.scriptLoaded();
-
如果是
<script type="module">逻辑代码</script>
的方式,可以直接使用动态import的特性<script type="module"> import('script.js').then((module) => { // script.js文件加载完成之后执行的逻辑代码 }); </script>
-