不是吧,沟通的async、defer都搞不清楚你就敢写熟练HTML啊??

2024-11-17 09:01   重庆  

点击关注公众号,“技术干货” 及时达!

前言

回想起当年面试时面试官问我:你简历上说熟练HTML,那么说说scriptasync、defer的区别吧。当时一下就蒙了,心想工作中好像从来没有用到过啊,那次之后我细细查阅资料才彻底理解它们的作用和区别。

这算是很经典面试题了,这面试题目没有难度,但却可以体现一个前端的基本功水平,因此下面除了文字讲解外还会配合官方的图片和博主自定义的示例,便于更深刻理解。

先汇总一下在 HTML 中的 script会有这三种用法,然后下面一一说明。

  • 默认按顺序执行用法: <script src='https://...'></script>
  • 脚本下载完马上执行用法: <script src='https://...' async></script>
  • 脚本下载完最后执行用法: <script src='https://...' defer></script>

script

「解释:」 当浏览器正在执行解析 HTML 代码块时,如果遇到默认的 script 标签,就会阻塞从而暂停解析 HTML 的剩余代码,去加载该 javascript 脚本,脚本加载完成之后会立即执行脚本,最后继续解析 HTML 代码。

配合下图理解更直观。

再看看如下示例代码解释

<html lang="zh">
<head>
<script>
console.log("Hello log~");
</script>
<script lay-src="https://.../Chart.min.js"></script>
<script lay-src="https://.../moment.min.js"></script>
<script lay-src="https://.../vue.min.js"></script>
</head>
<body>
您好,我是天天鸭的示例1
</body>
</html>

执行顺序会如下:

  • 执行打印:console.log("Hello log~");
  • 下载并执行Chart外部脚本:Chart.min.js
  • 下载并执行moment外部脚本:moment.min.js
  • 下载并执行vue外部脚本:vue.min.js
  • 显示文本内容:您好,我是天天鸭的示例1

「注意:」 默认script会按顺序执行脚本,如果中间有一个脚本执行时间长, 后续的脚本就会排队,HTML也停止解析等待执行完成,这时会有白屏情况出现。

script async

「解释:」 当浏览器正在执行解析 HTML 代码块时,如果遇到 script 标签并且标识是async,不会阻塞解析 HTML的剩余代码, 而是异步请求去加载该 javascript 脚本,但脚本加载完成之后会立即执行脚本并且此时会阻塞停止解析HTML,最后执行完脚本继续解析 HTML 代码。

配合下图理解更直观。

再看看如下示例代码解释

<html lang="zh">
<head>
<script>
console.log("Hello log~");
</script>
<script async lay-src="https://.../Chart.min.js" ></script>
<script async lay-src="https://.../moment.min.js"></script>
<script async lay-src="https://.../vue.min.js"></script>
</head>
<body>
您好,我是天天鸭的示例2
</body>
</html>

执行顺序会如下:

  • 执行打印:console.log("Hello log~");
  • 异步下载Chart.min.js、moment.min.jsvue.min.js脚本,此时HTML正常解析中
  • 下载完开始脚本,此时阻塞HTML解析
  • 最后接着解析剩下HTML

「注意:」async标识的script会在执行脚本时阻塞HTML解析,但下载脚本时不会,所以如果页面HTML结构比较简单那么会在脚本下载过程中就已经执行完成,因此上述例子是屏幕先显示您好,我是天天鸭的示例2,再执行脚本。

如果HTML结构复杂且量大解析时间较长,会在脚本执行时中断,执行完成接着解析。

script defer

「解释:」 当浏览器正在执行解析 HTML 代码块时,如果遇到有 script 标签并且标识是defer,不会阻塞解析 HTML 的剩余代码, 而是异步请求去加载该 javascript 脚本,但脚本加载完成之后并不会立即执行脚本,直到最后解析完 HTML 代码,最后再去执行脚本。

配合下图理解更直观。

再看看如下示例代码解释

<html lang="zh">
<head>
<script>
console.log("Hello log~");
</script>
<script defer lay-src="https://.../Chart.min.js" ></script>
<script defer lay-src="https://.../moment.min.js"></script>
<script defer lay-src="https://.../vue.min.js"></script>
</head>
<body>
您好,我是天天鸭的示例3
</body>
</html>

执行顺序会如下:

  • 执行打印:console.log("Hello log~");
  • 异步下载Chart.min.js、moment.min.jsvue.min.js脚本,此时HTML正常解析中
  • 下载完脚本后不会立即执行,等待HTML全部解析完显示文本内容:您好,我是天天鸭的示例3
  • 最后执行脚本

「注意:」  如果多个defer脚本,浏览器会并行下载,无论下载速度的快慢都不影响执行的顺序,会按HTML中出现的顺序依次执行。

混合使用

真实场景可以会几种方法混用,示例如下。

<html lang="zh">
<head>
<script>
console.log("Hello log~");
</script>
<script defer lay-src="https://.../Chart.min.js" ></script>
<script async lay-src="https://.../moment.min.js"></script>
<script defer lay-src="https://.../vue.min.js"></script>
</head>
<body>
您好,我是天天鸭的示例4
</body>
</html>

执行顺序会如下:

  • 执行打印:console.log("Hello log~");
  • 异步下载Chart.min.js、moment.min.jsvue.min.js脚本
  • 因为HTML比较简单,脚本下载过程中就执行完成了,显示文本内容:您好,我是天天鸭的示例4。
  • moment.min.js脚本下载完成后马上执行
  • Chart.min.jsvue.min.js会在HTML解析完成后执行

小结

  • 原生script阻塞HTML的解析,按顺序执行
  • defer不阻塞HTML的解析,并且脚本按HTML的顺序执行,HTML解析完才执行脚本
  • async有可能阻塞HTML的解析,脚本按网络请求顺序执行,谁先下载完就先执行谁,不可控

因此,理论上如果脚本独立的与其它资源加载没有关联可以选择async(可能会阻塞), 但脚本之间存在依赖关系需要选择defer

「注意:」 如果同时存在async,defer属性,async优级更高

好啦先写到这时,如果那里写的不好或者不对,欢迎指出。

点击关注公众号,“技术干货” 及时达!

稀土掘金技术社区
掘金,一个帮助开发者成长的技术社区
 最新文章