JavaScript <script> 标签在主流浏览器中执行顺序不保证的问题

背景介绍

当我们在 HTML 页面中引入多个 JavaScript 文件时,我们会使用 <script> 标签将它们包含进来。然而,在实际开发中,我们可能会遇到这样一种情况:代码按照我们写的顺序执行,但是在某些浏览器中,执行顺序并不能保证。

例如,我们有以下两个 JavaScript 文件:

------- ------------------------
------- ------------------------

如果 file1.js 中定义了一个函数,并在 file2.js 中调用了该函数,那么在某些浏览器中,由于执行顺序不确定,可能会出现函数未定义的错误。

原因分析

在了解原因之前,需要先了解一下 HTML 的解析过程。当浏览器遇到 <script> 标签时,它会暂停 HTML 的解析,开始下载 script 文件,然后执行文件中的代码,最后再继续解析 HTML。这就意味着,如果某个 script 文件执行时间较长,后续的 HTML 解析就会被阻塞,页面加载速度也会受到影响。

为了解决这个问题,浏览器通常会采用以下两种方式:

  1. 并行下载:浏览器会同时下载多个 script 文件,以提高页面加载速度。
  2. 延迟执行:浏览器会等待 HTML 解析完成后,再去执行 script 文件中的代码。

这两种方式都会导致 script 文件的执行顺序不确定。

解决方案

为了保证 JavaScript 文件的执行顺序,我们可以采用以下几种方法:

1. 使用 defer 属性

<script> 标签中添加 defer 属性,浏览器就会延迟执行该文件中的代码,直到 HTML 解析完成。例如:

------- -------------- ---------------
------- -------------- ---------------

这样就能保证 file1.js 先于 file2.js 执行。

2. 使用 async 属性

<script> 标签中添加 async 属性,浏览器会并行下载 script 文件,并在下载完成后立即执行其中的代码。例如:

------- -------------- ---------------
------- -------------- ---------------

这种方式不能保证 file1.js 先于 file2.js 执行,但对于某些场景,可以提高页面加载速度。

3. 改变代码结构

如果不能使用以上两种方式,我们还可以考虑改变代码结构,将依赖关系明确地表达出来。例如:

------- ------------------------
--------
  -------------------------
---------
------- ------------------------

这样就能保证 functionDefinedInFile1()file2.js 中调用时已经定义了。

总结

在实际开发中,需要注意 JavaScript 文件的执行顺序。通过使用 deferasync 属性,或者改变代码结构,可以解决该问题。同时,也需要充分了解 HTML 解析过程,以优化页面加载速度。

参考文献: