likes
comments
collection
share

HTML中 JavaScript 的加载方式(defer、async)

作者站长头像
站长
· 阅读数 20

HTML中 JavaScript 的加载方式


前言

相信各位前端的小伙伴都用过script元素,今天我们就来好好聊一聊它。


script元素

将JavaScript插入HTML的主要方法是使用〈〉元素,有下列8个属性

属性名状态描述
async可选表示应该立即下载脚本,但不能阻止其他页面动作,只对外部脚本文件有效
charset可选使用src属性指定的代码字符集(很少用,大部分浏览器不在乎)
crossorigin可选配置相关请求的cors设置,默认不用
defer可选表示在文档解析和显示完成后再执行脚本,只对外部脚本文件有效
integrityr可选允许比对接收道德资源和指定的加密签名以验证子资源的完整性,若接收子资源的加密签名与属性指定签名不匹配,则页面报错
language废弃最初用于表示代码块中的脚本语言
src可选表示要执行的代码的外部文件
type可选表示代码块中脚本语言的内容属性

src的优先级高于行内代码:使用了src属性的script元素,如果再在标签内包含其它javascript代码,会忽略行内代码。

<script src="xxx">
// 代码无效
function fn() {}
</script>

script 标签位置

head 标签内

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script>
    // ···js代码···
  </script>
</head>
<body>
</body>
</html>

但是这样意味着必须把所有 javascript 代码都下载、解析和解释完成后,才能开始渲染页面。当 javascript 代码很多的时候,会导致明显的渲染延迟

body 标签中页面内容后面

因为放在 head 标签内有如上渲染延迟问题,所以可以放在 body 标签中页面内容后面,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>
    <!-- 页面元素 -->
  </div>
  <script>
    // ···js代码···
  </script>
</body>
</html>

但是这样也会有问题无法复用逻辑,例如:我在 A 页面用到了加法逻辑,在 B 页面用到了相同的逻辑,但是由于 javascript 代码写在每个页面的 html 文件内,所以我不得不在两个页面写两段重复的代码,当这样的代码越来越多时,就会影响加载 javascript 代码的效率,

引入外部 javascript 代码

将 javascript 代码单独写在 js 文件内,哪个页面使用就引入该文件。

src工作原理

<script src="http://www.somewhere.com/file/js"></script>

当浏览器在解析这个资源的时候,会向 src 属性指定的路径发送一个 get 请求,以取得相应的资源,src 不受同源策略限制,jsonp 跨域就利用这个特性。

引入外部 javascript 代码的方式

推迟执行脚本

defer属性。这个属性表示会立即下载 src引入的资源文件(不会阻断解析HTML),当页面解析完毕后,再执行脚本。当同时有多个script元素使用了该属性,会按照它们出现的顺序执行

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="test1.js"></script>
  <script src="test2.js"></script>
  <title>Document</title>
</head>
<body>
</body>
</html>

例如上面的结构,在页面加载完成后执行外部资源文件时会先执行test1.js再执行test2.js.

异步执行脚本

async属性:这个属性表示会立即下载 src引入的资源文件,下载完成后立即执行,可能会阻断HTML解析,与defer不同的是当同时有多个script元素使用了该属性,不能保证会按照它们出现的顺序执行。因此,使用该属性重点在于引入的资源文件之间没有依赖关系。

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="test1.js"></script>
  <script src="test2.js"></script>
  <title>Document</title>
</head>
<body>
</body>
</html>

例如上面的结构,在页面加载完成后执行外部资源文件时也许会先执行test2.js再执行test1.js.

动态加载脚本

// 创建script
let script = document.createElement('script');
// 设置src属性
script.src = 'gibberish.js';
// 插入到head标签中
document.head.appendChild(script);

在将script插入到DOM且执行到这段代码之前不会发送请求下载src引入的资源。以这种方式创建的script是异步加载的,相当于添加了async属性。 问题:不是所有浏览器都支持async属性

可将其设置为同步加载

let script = document.createElement('script');
script.src = 'gibberish.js';
// 设置为同步加载
script.async = false;
document.head.appendChild(script);

问题:但是以这种方式获取资源对浏览器预加载器是不可见的,会严重影响它们在资源获取队列中的优先级,可能会严重影响性能。 解决办法:在文档头部显示的声明src引入的资源文件。

<link rel="preload" href="gibberish.js">

XHTML中的变化

在XHTML中使用 JavaScript 必须指定type属性且值为text/javascript,HTML中则可以没有这个属性。 在XHTML中语句a < b中的 < 会被解释成一个标签的开始,又因为作为标签开始的小于号后不能有空格,所以会导致语法错误。 有两种解决办法:

  1. 将代码中所有<换成对应HTML实体形式&lt;
  2. 将代码写在一个CDATA块中,CDATA快表示其内容不作为标签来解析。

在不支持CDATA块的非XHTML兼容浏览器中必须注释CDATA标记,下面这种格式适用于所有线代浏览器。

<script type="text/javascript">
//<![CDATA[
    function fn (a, b) {
      if (a < b) {
        return a - b;
      } else {
        return b - a;
      }
    }
//  ]]
</script>

开发最佳实践

虽然可以直接在HTML文件中嵌入JavaScript代码,但是通常认为最佳实践是尽可能将JavaScript代码放在外部文件。 外部文件的优势:

  1. 可维护性:一个目录中保存所有的JavaScript文件,比分散在HTML中更容易维护。
  2. 缓存:浏览器会根据特定的设置缓存所有的外部连接的JavaScript文件,当其他页面再用到该文件时不用下载,页面加载跟快。
  3. 适应未来:包含外部JavaScript文件的语法在HTML和XHTML中是一样的。

总结

script 标签中 defer 和 async 的区别

  • script :会阻碍 HTML 解析,只有下载好并执行完脚本才会继续解析 HTML。 HTML中 JavaScript 的加载方式(defer、async)
  • async script :解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。不一定按顺序执行脚本。 HTML中 JavaScript 的加载方式(defer、async)
  • defer script:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。

HTML中 JavaScript 的加载方式(defer、async)

  • 动态加载脚本:相当于添加了async属性,但可能会影响属性。

为了提高项目的可维护性,在开发中尽量将javascript代码写在外部文件中再引入使用。 非常感谢这篇文章给予的帮助

我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

转载自:https://juejin.cn/post/7154366358132785160
评论
请登录