<script>: 脚本元素

Baseline 广泛可用 *

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

* 此特性的某些部分可能存在不同级别的支持。

<script> HTML 元素用于嵌入可执行代码或数据;通常用于嵌入或引用 JavaScript 代码。<script> 元素也可以与其他语言一起使用,例如 WebGL 的 GLSL 着色器编程语言和 JSON

属性

此元素包含全局属性

async

对于经典脚本,如果存在 async 属性,则经典脚本将与解析并行获取,并尽快进行评估。

对于模块脚本,如果存在 async 属性,则脚本及其所有依赖项将与解析并行获取,并尽快进行评估。

警告: 对于经典脚本,如果缺少 src 属性(即用于内联脚本),则不得使用此属性,在这种情况下它将无效。

此属性允许消除阻塞解析器的 JavaScript,在这种情况下,浏览器必须在继续解析之前加载和评估脚本。defer 在这种情况下具有类似的效果。

如果该属性与 defer 属性一起指定,则该元素将表现得如同仅指定了 async 属性一样。

这是一个布尔属性:元素上布尔属性的存在表示真值,属性的缺失表示假值。

有关浏览器支持的说明,请参阅浏览器兼容性。另请参阅 asm.js 的异步脚本

attributionsrc 实验性

指定您希望浏览器随脚本资源请求一起发送 Attribution-Reporting-Eligible 标头。在服务器端,这用于触发在响应中发送 Attribution-Reporting-Register-SourceAttribution-Reporting-Register-Trigger 标头,以分别注册基于 JavaScript 的归因源归因触发器。应返回哪个响应标头取决于触发注册的 Attribution-Reporting-Eligible 标头的值。

注意: 另外,基于 JavaScript 的归因源或触发器可以通过发送包含 attributionReporting 选项的 fetch() 请求(直接在 fetch() 调用上设置或在传递给 fetch() 调用的 Request 对象上设置),或者通过发送调用了 setAttributionReporting()XMLHttpRequest 来注册。

您可以设置此属性的两个版本

  • 布尔值,即只有 attributionsrc 名称。这指定您希望将 Attribution-Reporting-Eligible 标头发送到 src 属性指向的同一服务器。当您在同一服务器上处理归因源或触发器注册时,这很好。注册归因触发器时,此属性是可选的,如果省略,将使用空字符串值。

  • 包含一个或多个 URL 的值,例如

    html
    <script
      src="myscript.js"
      attributionsrc="https://a.example/register-source https://b.example/register-source"></script>
    

    这在请求的资源不在您控制的服务器上,或者您只想在不同的服务器上处理归因源注册的情况下很有用。在这种情况下,您可以指定一个或多个 URL 作为 attributionsrc 的值。当资源请求发生时,Attribution-Reporting-Eligible 标头将除了资源源之外,还会发送到 attributionSrc 中指定的 URL。这些 URL 随后可以根据需要响应 Attribution-Reporting-Register-SourceAttribution-Reporting-Register-Trigger 标头以完成注册。

    注意:指定多个 URL 意味着可以在同一功能上注册多个归因源。例如,您可能正在尝试衡量不同广告系列的成功,这涉及生成关于不同数据的不同报告。

有关更多详细信息,请参阅 归因报告 API

阻塞

此属性明确指示某些操作应在脚本执行之前被阻塞。要阻塞的操作必须是空格分隔的阻塞令牌列表。目前只有一个令牌

  • render: 屏幕上的内容渲染被阻塞。

注意: 只有文档 <head> 中的 script 元素才可能阻塞渲染。脚本默认不阻塞渲染;如果 script 元素不包含 type="module"asyncdefer,则它会阻塞解析,而不是渲染。如果此类 script 元素通过脚本动态添加,则必须设置 blocking = "render" 才能使其阻塞渲染。

crossorigin

对于不通过标准 CORS 检查的脚本,普通 script 元素向 window.onerror 传递最少的信息。为了允许使用单独域进行静态媒体的站点进行错误日志记录,请使用此属性。有关其有效参数的更详细说明,请参阅CORS 设置属性

defer

此布尔属性用于指示浏览器,脚本应在文档解析后但在触发 DOMContentLoaded 事件之前执行。

带有 defer 属性的脚本将阻止 DOMContentLoaded 事件触发,直到脚本加载并完成评估。

警告: 如果缺少 src 属性(即用于内联脚本),则不得使用此属性,在这种情况下它将无效。

defer 属性对模块脚本无效——它们默认会延迟。

带有 defer 属性的脚本将按照它们在文档中出现的顺序执行。

此属性允许消除阻塞解析器的 JavaScript,在这种情况下,浏览器必须在继续解析之前加载和评估脚本。async 在这种情况下具有类似的效果。

如果该属性与 async 属性一起指定,则该元素将表现得如同仅指定了 async 属性一样。

fetchpriority

提供在获取外部脚本时要使用的相对优先级的提示。允许的值

high

以相对于其他外部脚本的较高优先级获取外部脚本。

low

以相对于其他外部脚本的较低优先级获取外部脚本。

auto

不对获取优先级设置偏好。这是默认值。如果未设置值或设置了无效值,则使用此值。

有关更多信息,请参阅 HTMLScriptElement.fetchPriority

integrity

此属性包含内联元数据,用户代理可以使用它来验证获取的资源是否已在没有意外操作的情况下交付。当 src 属性缺失时,不得指定此属性。请参阅子资源完整性

nomodule

此布尔属性用于指示在支持 ES 模块的浏览器中不应执行该脚本——实际上,这可以用于向不支持模块化 JavaScript 代码的旧版浏览器提供回退脚本。

nonce

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

referrerpolicy

指示在获取脚本或脚本获取的资源时要发送的 引用者

  • no-referrer:将不发送 Referer 头。
  • no-referrer-when-downgrade:将不向没有 TLS (HTTPS) 的发送 Referer 头。
  • origin:发送的引用者将仅限于引用页面的源:其方案主机端口
  • origin-when-cross-origin:发送到其他源的引用者将仅限于方案、主机和端口。同一源上的导航仍将包含路径。
  • same-origin:将为同源发送引用者,但跨域请求将不包含引用者信息。
  • strict-origin:仅当协议安全级别保持不变 (HTTPS→HTTPS) 时,才将文档的源作为引用者发送,但不要将其发送到安全性较低的目标 (HTTPS→HTTP)。
  • strict-origin-when-cross-origin(默认):执行同源请求时发送完整 URL,仅当协议安全级别保持不变 (HTTPS→HTTPS) 时发送源,不向安全性较低的目标 (HTTPS→HTTP) 发送任何头。
  • unsafe-url:引用者将包含源路径(但不包含片段密码用户名)。此值不安全,因为它会将 TLS 保护资源的源和路径泄漏到不安全的源。

注意: 空字符串值("")是默认值,也是在不支持 referrerpolicy 时使用的回退值。如果 referrerpolicy 未在 <script> 元素上显式指定,它将采用更高级别的引用者策略,即在整个文档或域上设置的策略。如果更高级别的策略不可用,则空字符串被视为等同于 strict-origin-when-cross-origin

src

此属性指定外部脚本的 URI;这可以作为直接在文档中嵌入脚本的替代方案。

type

此属性指示所代表的脚本类型。此属性的值将是以下之一

属性未设置(默认),空字符串,或 JavaScript MIME 类型

表示脚本是“经典脚本”,包含 JavaScript 代码。如果脚本引用的是 JavaScript 代码而不是指定 MIME 类型,建议作者省略该属性。JavaScript MIME 类型在 IANA 媒体类型规范中列出

importmap

此值表示元素主体包含一个导入映射。导入映射是一个 JSON 对象,开发人员可以使用它来控制浏览器在导入JavaScript 模块时如何解析模块说明符。

模块

此值导致代码被视为 JavaScript 模块。脚本内容的处理被延迟。charsetdefer 属性无效。有关使用 module 的信息,请参阅我们的JavaScript 模块指南。与经典脚本不同,模块脚本需要使用 CORS 协议进行跨域获取。

speculationrules 实验性

此值表示元素主体包含推测规则。推测规则采用 JSON 对象的形式,用于确定浏览器应预取或预渲染哪些资源。这是 推测规则 API 的一部分。

任何其他值

嵌入内容被视为数据块,不会被浏览器处理。开发人员必须使用有效的非 JavaScript MIME 类型来表示数据块。所有其他属性都将被忽略,包括 src 属性。

已弃用属性

charset 已弃用

如果存在,其值必须与 utf-8 进行 ASCII 不区分大小写的匹配。无需指定 charset 属性,因为文档必须使用 UTF-8,并且 script 元素继承其文档的字符编码。

language 已弃用 非标准

type 属性一样,此属性标识正在使用的脚本语言。然而,与 type 属性不同,此属性的可能值从未标准化。应改用 type 属性。

注意

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

脚本应以 text/javascript MIME 类型提供,但浏览器对此比较宽松,只有当脚本以图像类型(image/*)、视频类型(video/*)、音频类型(audio/*)或 text/csv 提供时才会阻止它们。如果脚本被阻止,则会向元素发送 error 事件;否则,会发送 load 事件。

示例

基本用法

此示例展示了如何使用 <script> 元素导入(外部)脚本

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

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

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

async 和 defer

使用 async 属性加载的脚本将在脚本获取时下载脚本,而不会阻塞页面。但是,一旦下载完成,脚本将执行,这会阻塞页面的渲染。这意味着在脚本执行完成之前,网页上的其余内容无法被处理和显示给用户。您无法保证脚本会以任何特定的顺序运行。当页面中的脚本彼此独立运行且不依赖于页面上的任何其他脚本时,最好使用 async

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

以下是不同脚本加载方法及其对页面意味着什么的视觉表示

How the three script loading method work: default has parsing blocked while JavaScript is fetched and executed. With async, the parsing pauses for execution only. With defer, parsing isn't paused, but execution on happens after everything is else is parsed.

此图片来自 HTML 规范,根据 CC BY 4.0 许可条款复制并裁剪为简化版本。

例如,如果您有以下脚本元素

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

您无法依赖脚本的加载顺序。jquery.js 可能在 script2.jsscript3.js 之前或之后加载,如果出现这种情况,这些脚本中任何依赖于 jquery 的函数都会产生错误,因为在脚本运行时 jquery 将未定义。

当您需要加载大量后台脚本并希望尽快将它们部署到位时,应该使用 async。例如,您可能有一些游戏数据文件需要加载,这些文件在游戏真正开始时会需要,但目前您只想继续显示游戏介绍、标题和大厅,而不希望它们被脚本加载阻塞。

使用 defer 属性加载的脚本(见下文)将按照它们在页面中出现的顺序运行,并在脚本和内容下载后立即执行它们

html
<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> 元素按照您希望浏览器执行它们的顺序放置。

模块回退

支持 type 属性的 module 值的浏览器会忽略任何带有 nomodule 属性的脚本。这使您能够使用模块脚本,同时为不支持的浏览器提供标记为 nomodule 的回退脚本。

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

使用 importmap 导入模块

在脚本中导入模块时,如果您不使用 type=importmap 功能,那么每个模块都必须使用绝对或相对 URL 的模块说明符进行导入。在下面的示例中,第一个模块说明符是绝对 URL,而第二个("./shapes/square.js")相对于文档的基本 URL 进行解析。

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

导入映射允许您提供一个映射,如果匹配,可以替换模块说明符中的文本。下面的导入映射定义了键 circlesquare,它们可以作为上面显示的模块说明符的别名。

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

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

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

有关导入映射功能的更多示例,请参阅 JavaScript 模块指南中的使用导入映射导入模块部分。

在 HTML 中嵌入数据

您还可以通过在 type 属性中指定有效的非 JavaScript MIME 类型,使用 <script> 元素通过服务器端渲染将数据嵌入 HTML。

html
<!-- Generated by the server -->
<script id="data" type="application/json">
  {
    "userId": 1234,
    "userName": "Maria Cruz",
    "memberSince": "2000-01-01T00:00:00.000Z"
  }
</script>

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

阻塞渲染直到脚本被获取和执行

您可以在 blocking 属性中包含 render 令牌;页面的渲染将被阻塞,直到脚本被获取和执行。在下面的示例中,我们阻塞了一个异步脚本的渲染,这样脚本就不会阻塞解析,但保证在渲染开始之前被评估。

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

技术摘要

内容类别 元数据内容流内容短语内容
允许内容 动态脚本,例如 text/javascript
标签省略 无,起始标签和结束标签都必须存在。
允许父级 任何接受元数据内容的元素,或任何接受短语内容的元素。
隐式 ARIA 角色 没有对应的角色
允许的 ARIA 角色 不允许 role
DOM 接口 HTMLScriptElement

规范

规范
HTML
# 脚本元素

浏览器兼容性

另见