<script> 元素这么基础,很多老手都不知道它可以写 ES6 模块代码

74 阅读3分钟

<script> 元素用作嵌入或者引用 JavaScript 代码,其自身支持 11 个属性:asynccrossorigindeferfetchpriorityintegritynomodulenoncereferrerpolicysrctypeblocking。其中有一些我们常用或者相对有意思的。

  1. async

    浏览器在解析 DOM 的时候,遇到存在 async 属性的 <script> 元素时,浏览器会继续解析 DOM(不阻塞 DOM 解析),并且并行地异步请求外联的 JS 资源,等到 JS 请求完成后会立马执行 JS 资源(此时会阻塞 DOM 的解析,并且无法保证 JS 资源的执行顺序,取决于资源大小和加载时的网络情况)。

  2. defer

    deferasync 属性的区别在于执行时机,两者都是异步并行下载,下载过程不会阻塞 DOM 解析,defer 属性标识的 JS 资源会在文档被解析后,触发 DOMContentLoaded(何时会触发此事件?留个思考,下篇文章将会说明) 事件之前执行。 注意:存在多个 <script> 元素同时使用 defer 时,会按照它们出现在文档中的顺序执行。

  3. nomodule

    <script> 元素设置此属性时,在不支持 ES 模块的浏览器会执行此 script 内的 JS 脚本。

  4. src

    大家都会的,值为外联 JS 脚本的地址。

  5. type

    如果是 JS 资源时,MDN 鼓励直接省略,因为 MIME 类型并没有跨浏览器标准化,无效或无法识别的 MIME 类型浏览器可能直接跳过相关代码。另外还有 2 个其他有意思的值:

    • module: 告诉浏览器我这段 script 代码是模块代码,要按照 ES6 模型那样写 import、export 等代码。模块代码默认是 defer 延后执行的。

      <script type="module">
          import { hello } from './utils.js';
      
          // 使用导入的函数
          hello();
      </script>
      
    • importmap: 导入映射表是一个 JSON 对象,开发者可以用它来控制浏览器在导入 JS 模块时如何解析模块标识符。

      <script type="importmap">
          {
              imports: {
                  moment: "./utils/es/moment.js",
                  antd: "./utils/es/antd.js"
              }
          }
      </script>
      <script type="module">
          import test from 'test';
          import test2 from 'test2';
      </script>
      

此外,需要注意或者了解的其他点有以下几个:

  1. 在使用行内 JS 代码时,要注意代码中不能出现字符串 </script> ,会误导浏览器解析导致报错:
   <script> 
       // 错误写法
       function error() { 
           console.log("</script>"); 
       } 

       // 正确写法
       function right() { 
           console.log("<\/script>");  // 在 / 前增加转义符 \
       } 
   </script>
  1. 解释执行 JS 代码会阻塞页面解析,例如: DOM 解析,样式解析;

  2. <script> 元素中的 src 属性的值不一定要是 .js 后缀的文件,浏览器不会校验后缀,但是为了保证浏览器能正确解析 JS 文件,服务器响应的 JS 文件的 Content-Type 必须是 JS MIME 类型;

image.png

  1. 如果既在 <script> 元素里面写了行内 JS 代码,也为其设置了 src 属性值,那么浏览器会忽略行内代码而是去下载 src 中的 JS 资源;

  2. 在没有设置 deferasync 属性的情况下,浏览器都会按照 <script> 在页面中出现的顺序下载和解析 JS 资源;

  3. <script> 元素放在 </body> 标签前面可以防止阻塞页面解析,避免导致页面白屏时间过长。

<!DOCTYPE html> 
<html> 
 <head> 
 <title>示例</title> 
 </head> 
 <body> 
 <!-- 这里是页面内容 --> 
 <script src="example.js"></script> 
 </body> 
</html>