Skip to content

Latest commit

 

History

History
284 lines (208 loc) · 16.7 KB

File metadata and controls

284 lines (208 loc) · 16.7 KB
title slug
<script>:脚本元素
Web/HTML/Element/script

{{HTMLSidebar}}

HTML <script> 元素用于嵌入可执行代码或数据,这通常用作嵌入或者引用 JavaScript 代码。<script> 元素也能在其他语言中使用,比如 WebGL 的 GLSL 着色器语言和 JSON

内容分类 元数据内容流式内容短语内容
允许的内容 动态脚本,如 text/javascript
标签省略 不允许,开始标签和结束标签都不能省略。
允许的父元素 任何可以接受元数据内容,或者短语内容的元素。
隐含的 ARIA 角色 没有对应的角色
允许的 ARIA 角色 不允许任何 role
DOM 接口 {{domxref("HTMLScriptElement")}}

属性

该元素包含全局属性

  • async

    • : 对于普通脚本,如果存在 async 属性,那么普通脚本会被并行请求,并尽快解析和执行。

      对于模块脚本,如果存在 async 属性,那么脚本及其所有依赖都会在延缓队列中执行,因此它们会被并行请求,并尽快解析和执行。

      该属性能够消除解析阻塞的 Javascript。解析阻塞的 Javascript 会导致浏览器必须加载并且执行脚本,之后才能继续解析。defer 在这一点上也有类似的作用。

      这是个布尔属性:布尔属性的存在意味着 true 值,布尔属性的缺失意味着 false 值。

      关于浏览器支持,请参见浏览器兼容性章节。另可参见 asm.js 的异步脚本文章。

  • crossorigin

    • : 正常的 script 元素将最小的信息传递给 {{domxref('Window.error_event', 'window.onerror')}},用于那些没有通过标准 {{Glossary("CORS")}} 检查的脚本。要允许对静态媒体使用独立域名的网站进行错误记录,请使用此属性。参见 CORS 设置属性,以获得对其有效参数的更多描述性解释。
  • defer

    • : 这个布尔属性的设置是为了向浏览器表明,该脚本是要在文档被解析后,但在触发 {{domxref("Document/DOMContentLoaded_event", "DOMContentLoaded")}} 事件之前执行的。

      包含 defer 属性的脚本将阻塞 DOMContentLoaded 事件触发,直到脚本完成加载并执行。

      [!WARNING] 本属性不应在缺少 src 属性的情况下使用(也就是内联脚本的情况下),这种情况下将不会生效。

      defer 属性对模块脚本也不会生效——它们默认是 defer 的。

      包含 defer 属性的脚本会按照它们出现在文档中的顺序执行。

      这个属性能够消除阻塞解析的 JavaScript,在这种情况下,浏览器必须在继续解析之前加载和执行脚本。async 在这种情况下也有类似的效果。

  • fetchpriority {{Experimental_Inline}}

    • : 提供一个指示,说明在获取外部脚本时要使用的相对优先级。允许的值:

      • high
        • : 获取该脚本的优先级比其他外部脚本的等级要高。
      • low
        • : 获取该脚本的优先级比其他外部脚本的等级要低。
      • auto
        • : 默认值:自动确定获取该脚本的相对优先级。
  • integrity

    • : 包含用户代理可用于验证所获取到资源的完整性的内联元数据。参见子资源完整性
  • nomodule

    • : 这个布尔属性被设置来标明这个脚本不应该在支持 ES 模块的浏览器中执行。实际上,这可用于在不支持模块化 JavaScript 的旧浏览器中提供回退脚本。
  • nonce

    • : 在 script-src Content-Security-Policy 中允许脚本的一个一次性加密随机数(nonce)。服务器每次传输策略时都必须生成一个唯一的 nonce 值。提供一个无法猜测的 nonce 是至关重要的,因为绕过一个资源的策略是微不足道的。
  • referrerpolicy

    • : 表示在获取脚本或脚本获取资源时,要发送哪个 referrer

      • no-referrer:不会发送 {{HTTPHeader("Referer")}} 标头。
      • no-referrer-when-downgrade(默认):如果没有 {{Glossary("TLS")}}({{Glossary("HTTPS")}})协议,{{HTTPHeader("Referer")}} 标头将不会被发送到{{Glossary("origin","源")}}上。
      • origin:发送的 referrer 将被限制在 referrer 页面的源:其协议、{{Glossary("host","主机")}}和{{Glossary("port","端口")}}。
      • origin-when-cross-origin:将会限制发送至其他源的 referrer 的协议、主机和端口号。在同源的导航上仍然包括路径。
      • same-origin:在{{Glossary("Same-origin policy", "同源")}}内将发送 referrer,但是跨源请求不包含 referrer 信息。
      • strict-origin:只在协议安全等级相同时(如 HTTPS→HTTPS)发送文档的源作为 referrer,目标安全性降低(如 HTTPS→HTTP)时不发送。
      • strict-origin-when-cross-origin:在执行同源请求时,发送完整的 URL,但只在协议安全级别保持不变(如 HTTPS→HTTPS)时发送源,而在目标安全性降低(如 HTTPS→HTTP)时不发送标头。
      • unsafe-url:referrer 将包含源路径(但不包含片段密码用户名)。这个值是不安全的,因为它将 TLS 保护的资源的源和路径泄露给不安全的源。

        [!NOTE] 空字符串("")既是默认值,也是在不支持 referrerpolicy 的情况下的一个回退值。如果没有在 <script> 元素上明确指定 referrerpolicy,它将采用更高级别的 referrer 策略,即对整个文档或域设置的策略。如果没有更高级别的策略,空字符串将被视为等同于 no-referrer-when-downgrade

  • src

    • : 这个属性定义引用外部脚本的 URI,这可以用来代替直接在文档中嵌入脚本。
  • type

    • : 该属性表示所代表的脚本类型。该属性的值可能为以下类型:
      • 属性未设置(默认),一个空字符串,或一个 JavaScript MIME 类型
        • : 代表脚本为包含 JavaScript 代码的“传统的脚本”。如果脚本指的是 JavaScript 代码,我们鼓励作者省略这个属性,而不是指定一个 MIME 类型。所有的 JavaScript MIME 类型都列在 IANA 的媒体类型规范中。
      • module
        • : 此值导致代码被视为 JavaScript 模块。其中的代码内容会延后处理。charsetdefer 属性不会生效。对于使用 module 的更多信息,请参见 JavaScript 模块指南。与传统代码不同的是,模块代码需要使用 CORS 协议来跨源获取。
      • importmap
        • : 此值代表元素体内包含导入映射(importmap)表。导入映射表是一个 JSON 对象,开发者可以用它来控制浏览器在导入 JavaScript 模块时如何解析模块标识符。
      • 任何其他值
        • : 所嵌入的内容被视为一个数据块,不会被浏览器处理。开发人员必须使用有效的 MIME 类型,但不是 JavaScript MIME 类型来表示数据块。所有其他属性,包括 src 均会被忽略。
  • blocking {{Experimental_Inline}}

    • : 这个属性明确指出,在获取脚本的过程中,某些操作应该被阻断。要阻断的操作必须是一个以空格分隔的列表,下面列出了阻断属性。
      • render:屏幕上渲染内容的操作应该被阻断。

废弃的属性

  • charset {{Deprecated_inline}}
    • : 如果存在,它的值必须是 ASCII 大小写不敏感的“utf-8”的匹配。没有必要指定 charset 属性,因为文档必须使用 UTF-8,而且 script 元素从文档继承其字符编码。
  • language {{Deprecated_inline}} {{Non-standard_Inline}}
    • : 和 type 属性类似,这个属性定义脚本使用的语言。但是与 type 不同的是,这个属性的可能值从未被标准化过。请用 type 属性代替这个属性。

备注

没有 asyncdefertype="module" 属性的脚本,以及没有 type="module" 属性的内联脚本,会在浏览器继续解析页面之前立即获取并执行。

脚本应该以 text/javascript 的 MIME 类型提供,但浏览器比较宽容,只有在脚本以图像类型(image/*)、视频类型(video/*)、音频类型(audio/*)或 text/csv 提供时才会阻止它们。如果脚本受阻,将向该元素发送 {{domxref("HTMLElement/error_event", "error")}} 事件;否则,将发送 {{domxref("HTMLElement/load_event", "load")}} 事件。

示例

基本用法

下面这些示例说明了如何使用 <script> 元素来导入(外部)脚本。

<script src="javascript.js"></script>

以下示例展示了如何向 <script> 元素内放入(内联)脚本。

<script>
  alert("Hello World!");
</script>

async 和 defer

使用了 async 属性加载的脚本不会在下载时阻塞页面。这意味着在脚本执行完成之前,将无法为用户处理和渲染网页上的其余内容。无法保证脚本的运行次序。当页面的脚本之间彼此独立,且不依赖于本页面的其他任何脚本时,async 是最理想的选择。

使用 defer 属性加载的脚本将按照它们在页面上出现的顺序加载。在页面内容全部加载完毕之前,脚本不会运行,如果脚本依赖于 DOM 的存在(例如,脚本修改了页面上的一个或多个元素),这一点非常有用。

以下是不同脚本加载方法的可视化表示,以及这对页面意味着什么:

三种脚本加载方法的工作原理:默认情况下,在获取和执行 JavaScript 时,解析过程被阻塞。使用 async 时,解析暂停,仅执行。使用 defer 时,解析不会暂停,但在解析完所有其他内容后才开始执行

该图片来自 HTML 规范,经过了复制和裁剪,以 CC BY 4.0 获得授权。

比如,如果你的页面要加载以下三个脚本:

<script async src="js/vendor/jquery.js"></script>
<script async src="js/script2.js"></script>
<script async src="js/script3.js"></script>

你不能依赖脚本的加载顺序。jquery.js 可能在 script2script3 之前或之后调用,如果这样,后两个脚本中依赖 jquery 的函数将产生错误,因为脚本运行时 jquery 尚未加载。

async 应该在有大量后台脚本需要加载,并且只想尽快加载到位的情况下使用。例如,你可能需要加载一些游戏数据文件,这在游戏真正开始时是需要的,但现在你只想显示游戏介绍、标题和大厅,而不想被脚本加载阻塞。

解决这一问题可使用 defer 属性,在脚本和内容下载后,脚本将按照在页面中出现的顺序加载和运行:

<script defer src="js/vendor/jquery.js"></script>
<script defer src="js/script2.js"></script>
<script defer src="js/script3.js"></script>

在第二个示例中,我们可以确保 jquery.js 必定在 script2.jsscript3.js 之前加载,同时 script2.js 必定在 script3.js 之前加载。在页面内容全部加载完成之前,它们不会运行,如果你的脚本依赖于 DOM(例如,它们修改了页面上的一个或多个元素),这将非常有用。

小结:

  • asyncdefer 都指示浏览器在页面的其他部分(DOM 等)正在下载时,在一个单独的线程中下载脚本,因此在获取过程中页面加载不会被阻塞。
  • 带有 async 属性的脚本将在下载完成后立即执行。这将阻塞页面,并不保证任何特定的执行顺序。
  • 带有 defer 属性的脚本将按照它们的顺序加载,并且只有在所有脚本加载完毕后才会执行。
  • 如果脚本应该立刻运行且没有任何依赖,那么应使用 async
  • 如果脚本需要等待页面解析,且依赖于其他脚本或 DOM,请使用 defer 加载脚本,并将关联的脚本按你想要浏览器加载它们的顺序置于相应 <script> 元素中。

模块回落

支持 module 作为 type 属性的浏览器忽略任何具有 nomodule 属性的脚本。这种机制可以允许你在使用模块脚本时为不支持的浏览器提供 nomodule 标记的回落脚本。

<script type="module" src="main.js"></script>
<script nomodule src="fallback.js"></script>

使用导入映射导入模块

在脚本中导入模块时,如果你不使用 type=importmap 特性,那么每个模块都必须使用模块指定符来导入,该指定符可以是绝对的也可以是相对的 URL。在下面的例子中,第一个模块标识符(“./shapes/square.js”)是相对于文档的根 URL 解析的,而第二个是绝对 URL。

import { name as squareName, draw } from "./shapes/square.js";
import { name as circleName } from "https://example.com/shapes/circle.js";

导入映射允许你提供一个映射,当匹配的时候,可以替换模块标识符文本。下面的导入映射定义了“square”和“circle”键,可以作为上述模块指定的别名。

<script type="importmap">
  {
    "imports": {
      "square": "./shapes/square.js",
      "circle": "https://example.com/shapes/circle.js"
    }
  }
</script>

这允许我们使用模块标识符中的名称导入模块(而不是绝对或相对的 URL)。

import { name as squareName, draw } from "square";
import { name as circleName } from "circle";

关于使用导入映射的更多例子,请参见 JavaScript 模块指南中的使用导入映射导入模块章节。

在 HTML 中嵌入数据

你也可以使用 <script> 元素来在 HTML 中嵌入服务端渲染的数据,在 type 属性中指定一个合法的非 JavaScript MIME 类型即可。

<!-- 由服务端生成 -->
<script id="data" type="application/json">
  {
    "userId": 1234,
    "userName": "Maria Cruz",
    "memberSince": "2000-01-01T00:00:00.000Z"
  }
</script>

<!-- 静态代码 -->
<script>
  const userInfo = JSON.parse(document.getElementById("data").text);
  console.log("User information: %o", userInfo);
</script>

在脚本被获取和执行之前阻止渲染

你可以在 blocking 属性中包含 render 标记;页面的渲染将被阻止,直到脚本被获取和执行。在下面的例子中,我们封锁了一个异步脚本的渲染、这样,脚本不会阻塞解析,但保证在渲染开始前被执行。

<script blocking="render" async src="async-script.js"></script>

规范

{{Specifications}}

浏览器兼容性

{{Compat}}

参见