进一步理解script元素

118 阅读3分钟

script元素

JavaScript插入HTML的主要方法是使用<script>标签。

script元素内部的代码从上而下依次执行。

在引入多个script元素的时候,浏览器会按照script元素在页面中的先后顺序进行解析,当上一个解析完成时,才会进行下一个script元素中的内容。

在HTML中使用JavaScript的两种方法:

// 第一种方法:直接在标签内使用javascript即可
<script>
    console.log('Hello World!')
</script>

// 第二种方法:引用外部文件
<script src="examplae.js"></script>

script元素常用属性

  • src:可选,用于引用外部javascript文件
  • type:可选,编写代码使用的脚本语言类型(也称MIME类型),默认值为text/javascript
  • async:可选,异步加载脚本,只对外部文件有效
  • defer:可选,延迟加载脚本,只对外部文件有效

延迟加载脚本和异步加载脚本

  • 延迟加载脚本defer

在script元素中设置了defer属性,表示脚本会被延迟到整个页面都解析完毕后再运行(也就是浏览器解析到结束的</html>标签后才执行),推迟的脚本原则上按照它们被列出的次序执行。

如下面代码所示: example2.js会在example1.js之后执行,两者都会在 DOMContentLoaded事件之前执行

<!DOCTYPE html>
<html>
  <head>
  <title>Example HTML Page</title>
  <script defer src="example1.js"></script>
  <script defer src="example2.js"></script>
  </head>
  <body>
  <!-- 这里是页面内容 -->
  </body>
</html>
  • 异步加载脚本 async

script元素中定义了async属性,表示脚本不需要等待其他脚本,同时也不阻塞文档渲染。(也就是告诉浏览器,不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本)。异步脚本保证会在页面的load事件前执行,但可能会在DOMContentLoaded之前或之后。

如下面代码所示: example2.js可能会先于example1.js执行,所以在使用async属性时,要避免两个js相互依赖。

<!DOCTYPE html>
<html>
  <head>
  <title>Example HTML Page</title>
  <script defer src="example1.js"></script>
  <script defer src="example2.js"></script>
  </head>
  <body>
  <!-- 这里是页面内容 -->
  </body>
</html>
  • DOMContentLoaded事件会在DOM树构建完成后立即触发,而不用等待图片、js文件、css文件或其他资源加载完成。
  • load事件会在整个页面(包括所有外部资源如图片、js文件和css文件)加载完成后触发。

动态加载脚本

除了<script>标签,通过想DOM中动态添加script元素同样指定脚本。只要创建一个script元素并将其添加到DOM即可。

let script = document.createElement('script');
script.src = 'example.js';
document.body.appendChild(script);

默认情况下,以这种方式创建的<script>元素是以异步方式加载的,相当于添加了async属性。

这样做可能会有一些问题:所有浏览器都支持createElement()方法,但并不是所有浏览器都支持async属性。因此,如果要统一动态脚本的加载行为,可以明确将其设置为同步加载:

let script = document.createElement('script');
script.src = 'example.js';
script.async = false;
document.body.appendChild(script);

以这种方式获取的资源对浏览器预加载器时不可见的,要想让预加载器知道这些动态请求文件的存在,可以在文档头部显示声明它们:

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

思考问题

为何要把js放在body最下面?

浏览器在解析到标签时才开始渲染页面,若把所有js文件都放在里,必须等到全部js代码被下载、解析和执行完成后,才能呈现页面的内容,这会导致浏览器窗口中很长一段时间是一片空白,影响用户体验。