1. 8 Web 应用 API
    1. 8.1 脚本
      1. 8.1.1 简介
      2. 8.1.2 代理和代理集群
        1. 8.1.2.1 与 JavaScript 代理形式的集成
        2. 8.1.2.2 与 JavaScript 代理集群形式的集成
      3. 8.1.3 领域及其对应物
        1. 8.1.3.1 环境
        2. 8.1.3.2 环境设置对象
        3. 8.1.3.3 领域、设置对象和全局对象
          1. 8.1.3.3.1 入口
          2. 8.1.3.3.2 在职
          3. 8.1.3.3.3 当前
          4. 8.1.3.3.4 相关
        4. 8.1.3.4 启用和禁用脚本
        5. 8.1.3.5 安全上下文
      4. 8.1.4 脚本处理模型
        1. 8.1.4.1 脚本
        2. 8.1.4.2 获取脚本
        3. 8.1.4.3 创建脚本
        4. 8.1.4.4 调用脚本
        5. 8.1.4.5 终止脚本
        6. 8.1.4.6 运行时脚本错误
        7. 8.1.4.7 未处理的 Promise 拒绝
        8. 8.1.4.8 导入映射解析结果
      5. 8.1.5 模块标识符解析
        1. 8.1.5.1 解析算法
        2. 8.1.5.2 导入映射
        3. 8.1.5.3 导入映射处理模型
      6. 8.1.6 JavaScript 规范主机钩子
        1. 8.1.6.1 HostEnsureCanAddPrivateElement(O)
        2. 8.1.6.2 HostEnsureCanCompileStrings(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg)
        3. 8.1.6.3 HostGetCodeForEval(argument)
        4. 8.1.6.4 HostPromiseRejectionTracker(promise, operation)
        5. 8.1.6.5 HostSystemUTCEpochNanoseconds(global)
        6. 8.1.6.6 与作业相关的宿主钩子
          1. 8.1.6.6.1 HostCallJobCallback(callback, V, argumentsList)
          2. 8.1.6.6.2 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry)
          3. 8.1.6.6.3 HostEnqueueGenericJob(job, realm)
          4. 8.1.6.6.4 HostEnqueuePromiseJob(job, realm)
          5. 8.1.6.6.5 HostEnqueueTimeoutJob(job, realm, milliseconds)
          6. 8.1.6.6.6 HostMakeJobCallback(callable)
        7. 8.1.6.7 与模块相关的宿主钩子
          1. 8.1.6.7.1 HostGetImportMetaProperties(moduleRecord)
          2. 8.1.6.7.2 HostGetSupportedImportAttributes()
          3. 8.1.6.7.3 HostLoadImportedModule(referrer, moduleRequest, loadState, payload)
      7. 8.1.7 事件循环
        1. 8.1.7.1 定义
        2. 8.1.7.2 排队任务
        3. 8.1.7.3 处理模型
        4. 8.1.7.4 通用任务来源
        5. 8.1.7.5 从其他规范处理事件循环
      8. 8.1.8 事件
        1. 8.1.8.1 事件处理程序
        2. 8.1.8.2 元素、Document 对象和 Window 对象上的事件处理程序
          1. 8.1.8.2.1 IDL 定义
        3. 8.1.8.3 事件触发
    2. 8.2 WindowOrWorkerGlobalScope 混合
    3. 8.3 Base64 实用程序方法

8 Web 应用 API

8.1 脚本

8.1.1 简介

各种机制会导致作者提供的可执行代码在文档的上下文中运行。这些机制包括但不限于:

8.1.2 代理和代理集群

8.1.2.1 与 JavaScript 代理形式的集成

JavaScript 定义了代理的概念。本节介绍该语言级概念在 Web 平台上的映射。

从概念上讲,代理概念是一个与架构无关的理想化“线程”,JavaScript 代码在其中运行。此类代码可能涉及多个全局/ 领域,这些全局/ 领域 可以同步访问彼此,因此需要在单个执行线程中运行。

两个具有相同代理的 Window 对象并不意味着它们可以直接访问彼此领域中创建的所有对象。它们必须具有相同的来源域;请参阅 IsPlatformObjectSameOrigin

Web 平台上存在以下类型的代理:

同源窗口代理

包含各种可能相互访问的 Window 对象,这些访问可能是直接的,也可能是通过使用 document.domain 实现的。

如果包含的代理集群的 is origin-keyed 属性为 true,则所有 Window 对象都将具有相同的来源,可以直接相互访问,并且 document.domain 将不执行任何操作。

两个具有相同来源的 Window 对象可以位于不同的同源窗口代理中,例如,如果它们各自位于自己的浏览上下文组中。

专用工作线程代理

包含单个 DedicatedWorkerGlobalScope 对象。

共享工作线程代理

包含单个 SharedWorkerGlobalScope 对象。

服务工作线程代理

包含单个 ServiceWorkerGlobalScope 对象。

Worklet 代理

包含单个 WorkletGlobalScope 对象。

虽然给定的 worklet 可以具有多个领域,但每个这样的领域都需要自己的代理,因为每个领域可以独立于其他领域执行代码,并且可以与其他领域同时执行代码。

只有共享和专用工作线程代理允许使用 JavaScript Atomics API 来潜在地阻止。

为了创建代理,给定一个布尔值 canBlock:

  1. 令 signifier 为一个新的唯一内部值。

  2. 令 candidateExecution 为一个新的候选执行。

  3. 令 agent 为一个新的代理,其 [[CanBlock]] 为 canBlock,[[Signifier]] 为 signifier,[[CandidateExecution]] 为 candidateExecution,以及 [[IsLockFree1]]、[[IsLockFree2]] 和 [[LittleEndian]] 在实现的酌情决定下设置。

  4. 将 agent 的事件循环设置为一个新的事件循环。

  5. 返回 agent。

对于领域 realm,其 [[Signifier]] 为 realm.[[AgentSignifier]] 的代理是领域的代理。

平台对象 platformObject 的相关代理是 platformObject 的相关领域的代理。

当前领域的代理等效于周围代理。

8.1.2.2 与 JavaScript 代理集群形式的集成

JavaScript 还定义了代理集群的概念,本标准通过在使用获取同源窗口代理或获取工作线程/worklet 代理算法创建代理时适当地放置代理来将其映射到 Web 平台。

代理集群概念对于定义 JavaScript 内存模型至关重要,特别是对于哪些代理可以共享 SharedArrayBuffer 对象的底层数据。

从概念上讲,代理集群概念是一个与架构无关的理想化“进程边界”,它将多个“线程”(代理)分组在一起。规范中定义的代理集群通常比用户代理中实现的实际进程边界更严格。通过在规范级别强制执行这些理想化的划分,我们确保 Web 开发人员看到与共享内存相关的互操作行为,即使面对用户代理进程模型的变化和改变。

一个 代理集群 有一个关联的 跨域隔离模式,它是一个 跨域隔离模式。它最初是 "none"。

一个 代理集群 有一个关联的 是否基于来源(一个布尔值),它最初是 false。


以下定义了 代理集群 的分配 同源窗口代理

一个 代理集群键 是一个 站点元组来源。如果没有 Web 开发人员采取措施来实现 基于来源的代理集群,它将是一个 站点

另一种说法是,一个 代理集群键 可以是一个 方案和主机 或一个 来源

获取同源窗口代理,给定一个 来源 origin,一个 浏览上下文组 group,以及一个布尔值 requestsOAC,执行以下步骤:

  1. site 为使用 origin 获取站点 的结果。

  2. keysite

  3. 如果 group跨域隔离模式 不是 "none",则将 key 设置为 origin

  4. 否则,如果 group历史代理集群键映射[origin] 存在,则将 key 设置为 group历史代理集群键映射[origin]。

  5. 否则

    1. 如果 requestsOAC 为 true,则将 key 设置为 origin

    2. group历史代理集群键映射[origin] 设置为 key

  6. 如果 group代理集群映射[key] 不存在,则

    1. agentCluster 为一个新的 代理集群

    2. agentCluster跨域隔离模式 设置为 group跨域隔离模式

    3. agentCluster是否基于来源 设置为 true,如果 key 等于 origin;否则为 false。

    4. 创建代理 的结果(给定 false)添加到 agentCluster 中。

    5. group代理集群映射[key] 设置为 agentCluster

  7. 返回 group代理集群映射[key] 中包含的单个 同源窗口代理

这意味着每个浏览上下文代理集群只有一个 同源窗口代理。(但是,专用工作者工作者代理 可能在同一个集群中。)


以下定义了所有其他类型代理的 代理集群 的分配。

获取工作者/工作者代理,给定一个 环境设置对象 或 null outside settings,一个布尔值 isTopLevel,以及一个布尔值 canBlock,执行以下步骤:

  1. agentCluster 为 null。

  2. 如果 isTopLevel 为 true,则

    1. agentCluster 设置为一个新的 代理集群

    2. agentCluster是否基于来源 设置为 true。

      这些工作者可以被认为是基于来源的。但是,这不会通过任何 API 公开(与 originAgentCluster 对窗口公开基于来源的方式不同)。

  3. 否则

    1. 断言outside settings 不是 null。

    2. ownerAgentoutside settings领域代理

    3. agentCluster 设置为包含 ownerAgent 的代理集群。

  4. agent 为给定 canBlock 创建代理 的结果。

  5. agent 添加到 agentCluster 中。

  6. 返回 agent。

获取专用/共享工作者代理,给定一个 环境设置对象 outside settings 以及一个布尔值 isShared,返回给定 outside settingsisShared 以及 true 获取工作者/工作者代理 的结果。

获取工作者代理,给定一个 环境设置对象 outside settings,返回给定 outside settings、false 以及 false 获取工作者/工作者代理 的结果。

获取服务工作者代理,返回给定 null、true 以及 false 获取工作者/工作者代理 的结果。


以下成对的全局对象都位于同一个 代理集群 中,因此可以使用 SharedArrayBuffer 实例相互共享内存

以下成对的全局对象不在同一个 代理集群 中,因此无法共享内存

8.1.3 领域及其对应物

JavaScript 规范引入了 领域 概念,表示运行脚本的全局环境。每个领域都带有一个 实现定义的 全局对象;本规范的大部分内容都致力于定义该全局对象及其属性。

对于 Web 规范,将值或算法与领域/全局对象对关联起来通常很有用。当值特定于特定类型的领域时,它们直接与相关的全局对象关联,例如,在 WindowWorkerGlobalScope 接口的定义中。当值在多个领域中都有效时,我们使用 环境设置对象 概念。

最后,在某些情况下,需要在领域/全局对象/环境设置对象甚至不存在之前跟踪关联的值(例如,在 导航 期间)。这些值在 环境 概念中跟踪。

8.1.3.1 环境

一个 环境 是一个对象,它标识当前或潜在的执行环境的设置(即,导航参数保留环境请求保留客户端)。一个 环境 具有以下字段

一个 id

一个不透明的字符串,它唯一标识此 环境

一个 创建 URL

一个 URL,它表示与该 环境 关联的资源的位置。

Window 环境设置对象 的情况下,此 URL 可能与其 全局对象关联的 DocumentURL 不同,这是由于 history.pushState() 等机制修改了后者。

一个 顶层创建 URL

Null 或一个 URL,它表示“顶层” 环境创建 URL。对于工作者和工作程序,它为 null。

一个 顶层来源

一个 目前 实现定义 值、null 或一个 来源。对于“顶层”潜在执行环境,它为 null(即,当还没有响应时);否则,它是“顶层” 环境来源。对于专用工作者或工作程序,它是其创建者的 顶层来源。对于共享工作者或服务工作者,它是 实现定义 值。

当涉及沙箱、工作者和工作程序时,这与 顶层创建 URL来源 不同。

一个 目标浏览上下文

Null 或 导航请求 的目标 浏览上下文

一个 活动服务工作者

Null 或一个 服务工作者,它 控制 环境

一个 执行就绪标志

一个标志,指示环境设置是否完成。它最初未设置。

规范可能会为环境定义 环境丢弃步骤。这些步骤以 环境 作为输入。

仅针对少数环境运行 环境丢弃步骤:那些永远不会变得执行就绪的环境,因为例如,它们无法加载。

8.1.3.2 环境设置对象

一个 环境设置对象 是一个 环境,它另外指定了以下算法

一个 领域执行上下文

一个 JavaScript 执行上下文,由使用该设置对象的所有 脚本 共享,即给定 领域 中的所有脚本。当我们 运行经典脚本运行模块脚本 时,此执行上下文成为 JavaScript 执行上下文堆栈 的顶部,在该堆栈之上会推送另一个特定于该脚本的执行上下文。(此设置确保 源文本模块记录Evaluate 知道要使用哪个领域。)

一个 模块映射

一个 模块映射,用于导入 JavaScript 模块。

一个 API 基本 URL

一个 URL,由使用此 环境设置对象 的脚本调用的 API 用于 解析 URL

一个 来源

一个 来源,用于安全检查。

一个 策略容器

一个 策略容器,包含用于安全检查的策略。

一个 跨源隔离能力

一个布尔值,表示使用此 环境设置对象 的脚本是否允许使用需要跨源隔离的 API。

一个 时间来源
一个用作与性能相关的 时间戳基线的数字。 [HRT]

一个 环境设置对象负责事件循环 是其 全局对象相关代理事件循环

8.1.3.3 领域、设置对象和全局对象

一个 全局对象 是一个 JavaScript 对象,它是 领域 的 [[GlobalObject]] 字段。

在本规范中,所有 领域 都是使用 全局对象 创建 的,这些全局对象要么是 WindowWorkerGlobalScopeWorkletGlobalScope 对象。

一个 全局对象 具有一个 处于错误报告模式 布尔值,它最初为 false。

一个 全局对象 具有一个 未决拒绝的承诺弱集,一个 集合,其中包含 Promise 对象,最初为空。此集合不得创建对其任何成员的强引用,并且实现可以在 实现定义 的方式下限制其大小,例如,当添加新条目时,从其中删除旧条目。

一个 全局对象 具有一个 即将被通知的拒绝的承诺列表,一个 列表,其中包含 Promise 对象,最初为空。


领域全局对象环境设置对象 之间始终存在一对一对应关系。

创建一个新的领域 在一个 代理 agent 中,可以选择性地包含创建全局对象或全局 this 绑定的指令,执行以下步骤

  1. 执行 InitializeHostDefinedRealm(),并提供创建全局对象和全局 this 绑定的定制化参数。

  2. realm execution context正在运行的 JavaScript 执行上下文

    这是在上一步骤中创建的 JavaScript 执行上下文

  3. JavaScript 执行上下文栈 中移除 realm execution context

  4. realmrealm execution context 的领域组件。

  5. 如果 agent代理集群跨域隔离模式 为 "none",那么

    1. globalrealm全局对象

    2. status 为 ! global.[[Delete]]("SharedArrayBuffer").

    3. 断言: status 为真。

    这样做是为了与 web 内容兼容,我们希望在未来能移除它。Web 开发者仍然可以通过 new WebAssembly.Memory({ shared:true, initial:0, maximum:0 }).buffer.constructor 获取构造函数。

  6. 返回 realm execution context


在整个规范中定义算法步骤时,通常需要说明要使用哪个 领域 — 或者等效地,要使用哪个 全局对象环境设置对象。通常,至少有四种可能性

入口
这对应于启动当前正在运行的脚本操作的脚本:即用户代理在调用作者代码时调用的函数或脚本。
现任
这对应于栈中最最近进入的作者函数或脚本,或者最初调度当前正在运行的回调的作者函数或脚本。
当前
这对应于当前正在运行的函数对象,包括可能没有用 JavaScript 实现的内置用户代理函数。(它源自 当前领域。)
相关
每个 平台对象 都有一个 相关领域,它大致相当于创建该对象的 领域。在编写算法时,最突出的 平台对象,其 相关领域 可能很重要,是当前正在运行的函数对象的 this 值。在某些情况下,可能存在其他重要的 相关领域,例如任何参数的领域。

注意 入口现任当前 概念在没有限定词的情况下就可以使用,而 相关 概念必须应用于特定的 平台对象

新的规范不应使用 现任入口 概念,因为它们过于复杂,使用起来不直观。我们正在努力从平台中移除几乎所有现有的使用方式:有关 现任 的信息,请参见 issue #1430,有关 入口 的信息,请参见 issue #1431

通常,web 平台规范应该使用 相关 概念,应用于正在操作的对象(通常是当前方法的 this 值)。这与 JavaScript 规范不符,在 JavaScript 规范中,当前 通常用作默认值(例如,在确定 领域Array 构造函数应用于在 Array.prototype.map 中构建结果时)。但是这种不一致已经深深地嵌入到平台中,以至于我们必须接受这种状态。

考虑以下页面,a.html 加载在浏览器窗口中,b.html 加载在 iframe 中(如所示),c.htmld.html 被省略(它们可以是空的文档)

<!-- a.html -->
<!DOCTYPE html>
<html lang="en">
<title>Entry page</title>

<iframe src="b.html"></iframe>
<button onclick="frames[0].hello()">Hello</button>

<!--b.html -->
<!DOCTYPE html>
<html lang="en">
<title>Incumbent page</title>

<iframe src="c.html" id="c"></iframe>
<iframe src="d.html" id="d"></iframe>

<script>
  const c = document.querySelector("#c").contentWindow;
  const d = document.querySelector("#d").contentWindow;

  window.hello = () => {
    c.print.call(d);
  };
</script>

每个页面都有自己的 浏览上下文,因此也拥有自己的 领域全局对象环境设置对象

当在响应 a.html 中按下按钮时调用 print() 方法时,

在大多数情况下,相关 概念比 当前 概念更适合用作默认选项,因为它更适合于创建要持久化并多次返回的对象。例如,navigator.getBattery() 方法在 Navigator 对象的 相关领域 中创建 promise,它被调用。这将产生以下影响:[BATTERY]

<!-- outer.html -->
<!DOCTYPE html>
<html lang="en">
<title>Relevant realm demo: outer page</title>
<script>
  function doTest() {
    const promise = navigator.getBattery.call(frames[0].navigator);

    console.log(promise instanceof Promise);           // logs false
    console.log(promise instanceof frames[0].Promise); // logs true

    frames[0].hello();
  }
</script>
<iframe src="inner.html" onload="doTest()"></iframe>

<!-- inner.html -->
<!DOCTYPE html>
<html lang="en">
<title>Relevant realm demo: inner page</title>
<script>
  function hello() {
    const promise = navigator.getBattery();

    console.log(promise instanceof Promise);        // logs true
    console.log(promise instanceof parent.Promise); // logs false
  }
</script>

如果 getBattery() 方法的算法改为使用 当前领域,那么所有结果都会颠倒。也就是说,在 outer.html 中第一次调用 getBattery() 之后,inner.html 中的 Navigator 对象将永久地存储在 outer.html领域 中创建的 Promise 对象,因此在 hello() 函数内部进行的类似调用将返回来自“错误”领域的 promise。由于这是不可取的,因此该算法改为使用 相关领域,从而得到上面注释中所示的合理结果。


本节的其余部分将正式定义 入口现任当前相关 概念。

8.1.3.3.1 入口

调用脚本 的过程将在 JavaScript 执行上下文栈 上推送或弹出 领域执行上下文,并穿插其他 执行上下文

有了这些内容,我们将 入口执行上下文 定义为 JavaScript 执行上下文栈 中最最近推送的 领域执行上下文入口领域入口执行上下文 的领域组件。

然后,入口设置对象入口领域环境设置对象

类似地,入口全局对象入口领域全局对象

8.1.3.3.2 现任

所有 JavaScript 执行上下文 必须在其代码评估状态中包含一个 跳过确定现任计数器 值,该值最初为零。在 准备运行回调清理运行回调后的结果 的过程中,此值将递增和递减。

每个 事件循环 都有一个关联的 备份当前设置对象栈,最初为空。简单来说,它用于在没有作者代码在栈上时确定 当前设置对象,但作者代码负责以某种方式运行当前算法。 准备运行回调运行回调后的清理 操作会操作这个栈。 [WEBIDL]

当使用 Web IDL 调用 作者代码,或者当 HostEnqueuePromiseJob 调用 Promise 任务时,它们使用以下算法来跟踪相关数据以确定 当前设置对象

准备运行一个回调,使用 环境设置对象 settings

  1. settings 推入 备份当前设置对象栈

  2. context最顶层的具有执行上下文的脚本

  3. 如果 context 不为空,则增加 context在确定当前时跳过的计数器

运行回调后的清理,使用 环境设置对象 settings

  1. context最顶层的具有执行上下文的脚本

    这将与 准备运行回调 相应调用中的 最顶层的具有执行上下文的脚本 相同。

  2. 如果 context 不为空,则减少 context在确定当前时跳过的计数器

  3. 断言备份当前设置对象栈 的最顶层条目为 settings

  4. 备份当前设置对象栈 中移除 settings

这里,最顶层的具有执行上下文的脚本JavaScript 执行上下文栈 中具有非空 ScriptOrModule 组件的最顶层条目,或者如果 JavaScript 执行上下文栈 中没有这样的条目,则为 null。

有了所有这些,当前设置对象 将按如下方式确定

  1. context最顶层的具有执行上下文的脚本

  2. 如果 context 为 null,或者如果 context在确定当前时跳过的计数器 大于零,则

    1. 断言备份当前设置对象栈 不为空。

      如果尝试从未由 调用脚本 或 Web IDL 调用 回调触发的算法中获取 当前设置对象,则此断言将失败。例如,如果尝试从定期运行作为 事件循环 一部分的算法中获取 当前设置对象,并且没有涉及作者代码,则会触发此断言。在这种情况下,无法使用 当前 概念。

    2. 返回 备份当前设置对象栈 的最顶层条目。

  3. 返回 context 的 Realm 组件的 设置对象

然后,当前 Realm当前设置对象Realm

同样,当前全局对象当前设置对象全局对象


以下一系列示例旨在说明所有不同机制如何共同定义 当前 概念

考虑以下入门示例

<!DOCTYPE html>
<iframe></iframe>
<script>
  frames[0].postMessage("some data", "*");
</script>

这里有两个有趣的 环境设置对象window 的和 frames[0] 的。我们关心的是:在执行 postMessage() 的算法时,当前设置对象 是什么?

它应该是 window 的,以捕捉这样的直观概念:导致算法执行的作者脚本是在 window 中执行,而不是 frames[0] 中。这是有道理的:窗口发送消息步骤 使用 当前设置对象 来确定生成的 source 属性,在本例中,window 绝对是消息的来源。

现在让我们解释一下上面给出的步骤如何让我们得到直观上想要的 window相关设置对象 的结果。

窗口发送消息步骤 查找 当前设置对象 时,最顶层的具有执行上下文的脚本 将是与 script 元素相对应的脚本:它是在 ScriptEvaluation 的过程中,作为 运行经典脚本 算法的一部分被推入 JavaScript 执行上下文栈 的。由于没有涉及 Web IDL 回调调用,因此上下文的 在确定当前时跳过的计数器 为零,因此它被用来确定 当前设置对象;结果是 window环境设置对象

(注意,frames[0]环境设置对象this 在调用 postMessage() 方法时相关的设置对象,因此参与确定消息的 目标。而当前则用于确定消息的 。)

考虑以下更复杂的示例

<!DOCTYPE html>
<iframe></iframe>
<script>
  const bound = frames[0].postMessage.bind(frames[0], "some data", "*");
  window.setTimeout(bound);
</script>

此示例与上一个示例非常相似,但通过 Function.prototype.bind 以及 setTimeout() 做了额外的间接操作。但是,答案应该相同:异步调用算法不应该改变 当前 概念。

这次,结果涉及更复杂的机制

bound 转换为 Web IDL 回调类型时,当前设置对象 是与 window 相对应的(与上面的入门示例中的方式相同)。Web IDL 将此存储为生成的回调值的 回调上下文

setTimeout() 发布的 任务 执行时,该任务的算法使用 Web IDL 来 调用 存储的回调值。Web IDL 反过来调用上面的 准备运行回调 算法。这将存储的 回调上下文 推入 备份当前设置对象栈。此时(在计时器任务内部)没有作者代码在栈上,因此 最顶层的具有执行上下文的脚本 为 null,并且没有东西会增加其 在确定当前时跳过的计数器

调用回调然后调用 boundbound 反过来调用 frames[0]postMessage() 方法。当 postMessage() 算法查找 当前设置对象 时,仍然没有作者代码在栈上,因为绑定函数只是直接调用内置方法。因此,最顶层的具有执行上下文的脚本 将为 null:JavaScript 执行上下文 栈只包含一个与 postMessage() 相对应的执行上下文,在其下方没有 ScriptEvaluation 上下文或类似的上下文。

这是我们回退到 备份当前设置对象栈 的地方。如上所述,它将包含 window相关设置对象 作为其最顶层条目。因此,它被用作在执行 postMessage() 算法时的 当前设置对象

考虑最后一个,甚至更复杂的示例

<!-- a.html -->
<!DOCTYPE html>
<button>click me</button>
<iframe></iframe>
<script>
const bound = frames[0].location.assign.bind(frames[0].location, "https://example.com/");
document.querySelector("button").addEventListener("click", bound);
</script>
<!-- b.html -->
<!DOCTYPE html>
<iframe src="a.html"></iframe>
<script>
  const iframe = document.querySelector("iframe");
  iframe.onload = function onLoad() {
    iframe.contentWindow.document.querySelector("button").click();
  };
</script>

同样,有两个有趣的 环境设置对象 在起作用:a.html 的和 b.html 的。当 location.assign() 方法触发 Location 对象导航 算法时,当前设置对象 会是什么?和以前一样,它直观上应该是 a.html 的:click 监听器最初是由 a.html 调度的,因此即使涉及 b.html 的某些东西导致监听器触发,负责的 当前 仍然是 a.html 的。

回调设置类似于前面的示例:当bound转换为Web IDL回调类型时,现任设置对象是对应于a.html的,它被存储为回调的回调上下文

click()方法在b.html内部被调用时,它分发一个click事件到a.html内部的按钮上。这一次,当准备运行回调算法作为事件分发的一部分执行时,堆栈中作者代码;最顶层的脚本执行上下文onLoad函数的,其跳过确定现任计数器被递增。此外,a.html环境设置对象(存储为EventHandler回调上下文)被推入备份现任设置对象堆栈

现在,当Location对象导航算法查找现任设置对象时,最顶层的脚本执行上下文仍然是onLoad函数的(因为我们使用绑定函数作为回调)。然而,它的跳过确定现任计数器值为1,因此我们回退到备份现任设置对象堆栈。这给了我们a.html环境设置对象,正如预期的那样。

请注意,这意味着即使是a.html内部的iframe进行导航,但实际上是a.html本身被用作源Document,它决定了包括请求客户端在内的其他事项。这是也许是web平台上唯一合理的现任概念使用场景;在所有其他情况下,使用它的后果只是令人困惑,我们希望有一天将它们切换为使用当前相关,具体取决于情况。

8.1.3.3.3 当前

JavaScript规范定义了当前领域,也称为“当前领域记录”。[JAVASCRIPT]

然后,当前设置对象当前领域环境设置对象

类似地,当前全局对象当前领域全局对象

8.1.3.3.4 相关

对于一个平台对象,其相关领域其[[Realm]]字段的值。

然后,对于一个平台对象 o,其相关设置对象o相关领域环境设置对象

类似地,对于一个平台对象 o,其相关全局对象o相关领域全局对象

8.1.3.4 启用和禁用脚本

当以下所有条件为真时,对于一个环境设置对象 settings脚本被启用

脚本被禁用对于一个环境设置对象,当脚本未启用时,即,当上述任何条件为假时。


脚本被启用对于一个节点node,如果node节点文档浏览上下文不为空,并且脚本被启用对于node相关设置对象

脚本被禁用对于一个节点,当脚本未启用时,即,当其节点文档浏览上下文为空,或者当脚本被禁用对于其相关设置对象

8.1.3.5 安全上下文

一个环境 environment是一个安全上下文,如果以下算法返回true

  1. 如果environment是一个环境设置对象,那么

    1. globalenvironment全局对象

    2. 如果global是一个WorkerGlobalScope,那么

      1. 如果global拥有者集[0]的相关设置对象是一个安全上下文,那么返回true。

        我们只需要检查第0项,因为它们必然都保持一致。

      2. 返回false。

    3. 如果global是一个WorkletGlobalScope,那么返回true。

      Worklet只能在安全上下文中创建。

  2. 如果URL是否可能值得信赖?在给定environment顶级创建URL的情况下返回“Potentially Trustworthy”,那么返回true。

  3. 返回false。

一个环境是一个非安全上下文,如果它不是一个安全上下文

8.1.4 脚本处理模型

8.1.4.1 脚本

一个脚本是两种可能的结构体之一(即,经典脚本模块脚本)。所有脚本都具有

一个设置对象

一个环境设置对象,包含与同一上下文中的其他脚本共享的各种设置。

一个记录

以下其中之一

一个解析错误

一个JavaScript值,仅在记录为null时有意义,表示相应的脚本源文本无法解析。

此值用于在创建脚本时内部跟踪直接解析错误,不应直接使用。相反,请参考重新抛出的错误来确定此脚本“出错的原因”。

一个重新抛出的错误

一个JavaScript值,表示将阻止评估成功的错误。任何尝试运行脚本都将重新抛出此错误。

这可能是脚本的解析错误,但在模块脚本的情况下,它可能是其依赖项之一的解析错误,或来自解析模块说明符的错误。

由于此异常值由JavaScript规范提供,我们知道它永远不会为null,因此我们使用null来表示未发生错误。

获取选项
null或脚本获取选项,包含与获取此脚本或它导入的模块脚本相关的各种选项。
一个基本URL

null或用于解析模块说明符的基本URL。当不为null时,它将是获取脚本的URL(对于外部脚本),或包含文档的文档基本URL(对于内联脚本)。

一个经典脚本是一种脚本,它具有以下附加的

一个静音错误布尔值

一个布尔值,如果为true,则表示不会为此脚本中的错误提供错误信息。这用于为跨域脚本静音错误,因为这可能会泄漏私密信息。

一个模块脚本是另一种类型的脚本。它没有额外的.

模块脚本可以分为四种类型

由于CSS样式表和JSON文档不导入依赖模块,并且在评估时不会抛出异常,因此CSS模块脚本JSON模块脚本获取选项基本URL始终为null。

以下算法确定活动脚本

  1. recordGetActiveScriptOrModule()。

  2. 如果record为null,则返回null。

  3. 返回record.[[HostDefined]]。

活动脚本概念到目前为止仅由import()功能使用,以确定用于解析相对模块说明符的基本URL

8.1.4.2 获取脚本

本节介绍了一些用于获取脚本的算法,它们需要各种必要的输入,并生成经典模块脚本


脚本获取选项是一个结构,具有以下

加密nonce

用于初始获取和获取任何导入模块的加密nonce元数据

完整性元数据

用于初始获取的完整性元数据

解析器元数据

用于初始获取和获取任何导入模块的解析器元数据

凭据模式

用于初始获取(对于模块脚本)和获取任何导入模块(对于模块脚本经典脚本)的凭据模式

推荐人策略

用于初始获取和获取任何导入模块的推荐人策略

此策略可以在收到模块脚本响应后发生变异,变为推荐人策略 解析响应,并在获取任何模块依赖项时使用。

渲染阻塞

用于初始获取和获取任何导入模块的渲染阻塞的布尔值。除非另有说明,否则其值为false。

获取优先级

用于初始获取的优先级

回想一下,通过import()功能,经典脚本可以导入模块脚本

默认脚本获取选项是一个脚本获取选项,其加密nonce为空字符串,完整性元数据为空字符串,解析器元数据为“not-parser-inserted”,凭据模式为“same-origin”,推荐人策略为空字符串,获取优先级为“auto”。

给定一个请求 request 和一个脚本获取选项 options,我们定义

设置经典脚本请求

request加密nonce元数据设置为options加密nonce,其完整性元数据设置为options完整性元数据,其解析器元数据设置为options解析器元数据,其推荐人策略设置为options推荐人策略,其渲染阻塞设置为options渲染阻塞,其优先级设置为options获取优先级

设置模块脚本请求

request加密 nonce 元数据 设置为 options加密 nonce,其 完整性元数据 设置为 options完整性元数据,其 解析器元数据 设置为 options解析器元数据,其 凭据模式 设置为 options凭据模式,其 推荐人策略 设置为 options推荐人策略,其 渲染阻塞 设置为 options渲染阻塞,以及其 优先级 设置为 options获取优先级

为了 获取后代脚本获取选项,给定一个 脚本获取选项 originalOptions,一个 URL url,以及一个 环境设置对象 settingsObject

  1. newOptionsoriginalOptions 的副本。

  2. integrity 为空字符串。

  3. 如果 settingsObject全局对象 是一个 Window 对象,则将 integrity 设置为使用 urlsettingsObject 解析模块完整性元数据 的结果。

  4. newOptions完整性元数据 设置为 integrity

  5. newOptions获取优先级 设置为 "auto"。

  6. 返回 newOptions

为了 解析模块完整性元数据,给定一个 URL url 和一个 环境设置对象 settingsObject

  1. 断言settingsObject全局对象 是一个 Window 对象。

  2. mapsettingsObject全局对象导入映射

  3. 如果 map完整性[url] 不 存在,则返回空字符串。

  4. 返回 map完整性[url]。


以下几种算法可以用 执行获取钩子 算法进行自定义,该算法接受一个 请求,一个布尔值 isTopLevel,以及一个 processCustomFetchResponse 算法。它使用一个 响应 和 null(失败)或包含响应体的 字节序列 来运行 processCustomFetchResponseisTopLevel 对所有 经典脚本 获取以及 获取外部模块脚本图获取模块工作者脚本图 的初始获取为真,但对图中遇到的 import 语句或 import() 表达式导致的获取为假。

默认情况下,不提供 执行获取钩子 将导致以下算法简单地 获取 给定的 请求,并对 请求 进行算法特定的自定义,并对生成的 响应 进行验证。

为了在这些算法特定的自定义之上叠加你自己的自定义,请提供一个 执行获取钩子,它修改给定的 请求获取 它,然后对生成的 响应 进行特定验证(如果验证失败,则使用 网络错误 完成)。

该钩子还可以用于执行更微妙的自定义,例如保留 响应 的缓存并完全避免执行 获取

服务工作者 是使用其自己的钩子选项运行这些算法的规范示例。 [SW]


现在开始介绍算法本身。

为了 获取经典脚本,给定一个 URL url,一个 环境设置对象 settingsObject,一个 脚本获取选项 options,一个 CORS 设置属性状态 corsSetting,一个 编码 encoding,以及一个算法 onComplete,运行以下步骤。 onComplete 必须是一个接受 null(失败)或 经典脚本(成功)的算法。

  1. request 为使用 url、"script" 和 corsSetting 创建潜在的 CORS 请求 的结果。

  2. request客户端 设置为 settingsObject

  3. request发起者类型 设置为 "script"。

  4. 使用 requestoptions 设置经典脚本请求

  5. 使用以下 processResponseConsumeBody 步骤 获取 request,给定 响应 response 和 null、失败或 字节序列 bodyBytes

    response 可以是 CORS 同源CORS 跨源。这只会影响错误报告的方式。

    1. response 设置为 response不安全响应

    2. 如果以下任何条件为真

      • bodyBytes 为 null 或失败;或者

      • response状态 不是 OK 状态

      则运行 onComplete,给定 null,并中止这些步骤。

      出于历史原因,此算法不像本节中的其他脚本获取算法那样包含 MIME 类型检查。

    3. potentialMIMETypeForEncoding 为使用 response标头列表 提取 MIME 类型 的结果。

    4. encoding 设置为使用 potentialMIMETypeForEncodingencoding 传统提取编码 的结果。

      这有意忽略了 MIME 类型本质

    5. sourceText 为使用 encoding 作为备用编码,将 bodyBytes 解码为 Unicode 的 解码 结果。

      解码 算法如果文件包含 BOM,则会覆盖 encoding

    6. 如果 responseCORS 跨源,则令 mutedErrors 为真,否则为假。

    7. script 为使用 sourceTextsettingsObjectresponseURLoptionsmutedErrorsurl 创建经典脚本 的结果。

    8. 运行 onComplete,给定 script

为了 获取经典工作者脚本,给定一个 URL url,一个 环境设置对象 fetchClient,一个 目标 destination,一个 环境设置对象 settingsObject,一个算法 onComplete,以及一个可选的 执行获取钩子 performFetch,运行以下步骤。 onComplete 必须是一个接受 null(失败)或 经典脚本(成功)的算法。

  1. request 为一个新的 请求,其 URLurl客户端fetchClient目标destination发起类型 为 "other",模式 为 "same-origin",凭据模式 为 "same-origin",解析器元数据 为 "not parser-inserted",并且其 使用 URL 凭据标志 已设置。

  2. 如果 performFetch 被给出,则使用 request、true 和下面定义的 processResponseConsumeBody 运行 performFetch

    否则,获取 request,并将 processResponseConsumeBody 设置为下面定义的 processResponseConsumeBody

    在这两种情况下,对于给定 响应 response 和 null、失败或 字节序列 bodyBytesprocessResponseConsumeBody,请执行以下算法

    1. response 设置为 response不安全响应

    2. 如果以下任何条件为真

      则运行 onComplete,给定 null,并中止这些步骤。

    3. 如果以下所有条件都为真

      则运行 onComplete,给定 null,并中止这些步骤。

      出于历史上的 Web 兼容性原因,其他 获取方案 免于 MIME 类型检查。将来我们可能能够对此进行收紧;请参阅 问题 #3255

    4. sourceTextUTF-8 解码 bodyBytes 的结果。

    5. script 为使用 sourceTextsettingsObjectresponseURL默认脚本获取选项 创建经典脚本 的结果。

    6. 运行 onComplete,给定 script

获取经典 worker 导入的脚本,请在给定 URL url环境设置对象 settingsObject 和可选的 执行获取钩子 performFetch 的情况下运行这些步骤。该算法将在成功时返回一个 经典脚本,或者在失败时抛出异常。

  1. response 为 null。

  2. bodyBytes 为 null。

  3. request 为一个新的 请求,其 URLurl客户端settingsObject目标 为 "script",发起类型 为 "other",解析器元数据 为 "not parser-inserted",并且其 使用 URL 凭据标志 已设置。

  4. 如果 performFetch 被给出,则使用 requestisTopLevel 和下面定义的 processResponseConsumeBody 运行 performFetch

    否则,获取 request,并将 processResponseConsumeBody 设置为下面定义的 processResponseConsumeBody

    在这两种情况下,对于给定 响应 res 和 null、失败或 字节序列 bbprocessResponseConsumeBody,请执行以下算法

    1. bodyBytes 设置为 bb

    2. response 设置为 res

  5. 暂停 直到 response 不为 null 为止。

    与本节中的其他算法不同,获取过程在此处是同步的。

  6. response 设置为 response不安全响应

  7. 如果以下任何条件为真

    则抛出一个 "NetworkError" DOMException

  8. sourceTextUTF-8 解码 bodyBytes 的结果。

  9. 如果 responseCORS-跨域,则令 mutedErrors 为 true,否则为 false。

  10. script 为给定 sourceTextsettingsObjectresponseURL默认脚本获取选项mutedErrors 创建经典脚本 的结果。

  11. 返回 script

获取外部模块脚本图,请在给定 URL url环境设置对象 settingsObject脚本获取选项 options 和算法 onComplete 的情况下运行这些步骤。onComplete 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。

  1. 禁止进一步的导入映射,给定 settingsObject

  2. 给定 urlsettingsObject、"script"、optionssettingsObject、"client"、true 和以下步骤(给定 result),获取单个模块脚本

    1. 如果 result 为 null,则使用 null 运行 onComplete,并中止这些步骤。

    2. 给定 settingsObject、"script" 和 onComplete获取并链接 result 的后代

获取 modulepreload 模块脚本图,请在给定 URL url目标 destination环境设置对象 settingsObject脚本获取选项 options 和算法 onComplete 的情况下运行这些步骤。onComplete 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。

  1. 禁止进一步的导入映射,给定 settingsObject

  2. 给定 urlsettingsObjectdestinationoptionssettingsObject、"client"、true 和以下步骤(给定 result),获取单个模块脚本

    1. 使用 result 运行 onComplete

    2. 如果 result 不为 null,则可以选择 获取并链接 result 的后代,给定 settingsObjectdestination 和一个空算法。

      通常,执行此步骤将有利于性能,因为它允许预加载将不可避免地稍后通过算法(如 获取外部模块脚本图 获取整个图)请求的模块。但是,用户代理可能希望在带宽受限的情况下或相关获取已经在进行的情况下跳过它们。

获取内联模块脚本图,请在给定 字符串 sourceTextURL baseURL环境设置对象 settingsObject脚本获取选项 options 和算法 onComplete 的情况下运行这些步骤。onComplete 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。

  1. 禁止进一步的导入映射,给定 settingsObject

  2. script 为使用 sourceTextsettingsObjectbaseURLoptions 创建 JavaScript 模块脚本 的结果。

  3. 给定 settingsObject、"script" 和 onComplete获取并链接 script 的后代

给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 凭证模式 credentialsMode、一个 环境设置对象 settingsObject 和一个算法 onComplete获取工作线程/模块工作线程脚本图,给定 urlfetchClientdestinationcredentialsModesettingsObjectonComplete

给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 凭证模式 credentialsMode、一个 环境设置对象 settingsObject、一个 模块响应映射 moduleResponsesMap 和一个算法 onComplete获取工作线程/模块工作线程脚本图,给定 urlfetchClientdestinationcredentialsModesettingsObjectonComplete 和以下 执行获取钩子,给定 requestprocessCustomFetchResponse

  1. requestURLrequestURL

  2. 如果 moduleResponsesMap[requestURL] 为 "fetching",则 并行等待 直到该条目的值发生变化,然后在 网络任务源排队一个任务 以继续执行以下步骤。

  3. 如果 moduleResponsesMap[requestURL] 存在,则

    1. cachedmoduleResponsesMap[requestURL]。

    2. 使用 cached[0] 和 cached[1] 运行 processCustomFetchResponse

    3. 返回。

  4. 设置 moduleResponsesMap[requestURL] 为 "fetching"。

  5. 获取 request,并将 processResponseConsumeBody 设置为以下步骤,给定 响应 response 和 null、失败或一个 字节序列 bodyBytes

    1. 设置 moduleResponsesMap[requestURL] 为 (responsebodyBytes)。

    2. 使用 responsebodyBytes 运行 processCustomFetchResponse


以下算法仅供本规范内部使用,作为 获取外部模块脚本图 或其他类似概念的一部分,其他规范不应直接使用它们。

此图说明了这些算法与上面算法以及彼此之间的关系

fetch an external module script graph fetch a modulepreload module script graph fetch an inline module script graph fetch a module worker script graph fetch a worklet script graph fetch a worklet/module worker script graph fetch the descendants of and link a module script

给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 凭证模式 credentialsMode、一个 环境设置对象 settingsObject、一个算法 onComplete 和一个可选的 执行获取钩子 performFetch,运行这些步骤。 onComplete 必须是一个接受 null(失败)或 模块脚本(成功)的算法。

  1. options 为一个 脚本获取选项,其 加密 nonce 为空字符串,完整性元数据 为空字符串,解析器元数据 为 "not-parser-inserted",凭证模式credentialsModereferrer 策略 为空字符串,获取优先级 为 "auto"。

  2. 获取单个模块脚本,给定 urlfetchClientdestinationoptionssettingsObject、"client"、true 和 onSingleFetchComplete,如下定义。如果给定 performFetch,则将其一同传递。

    onSingleFetchComplete 给定 result 为以下算法

    1. 如果 result 为 null,则使用 null 运行 onComplete,并中止这些步骤。

    2. 获取并链接 result 的后代,给定 fetchClientdestinationonComplete。如果给定 performFetch,则将其一同传递。

给定一个 模块脚本 moduleScript、一个 环境设置对象 fetchClient、一个 目标 destination、一个算法 onComplete 和一个可选的 执行获取钩子 performFetch获取并链接 它的后代,运行这些步骤。 onComplete 必须是一个接受 null(失败)或 模块脚本(成功)的算法。

  1. recordmoduleScript记录

  2. 如果 record 为 null,则

    1. moduleScript要重新抛出的错误 设置为 moduleScript解析错误

    2. 使用 moduleScript 运行 onComplete

    3. 返回。

  3. stateRecord { [[ParseError]]: null, [[Destination]]: destination, [[PerformFetch]]: null, [[FetchClient]]: fetchClient }。

  4. 如果给定 performFetch,则将 state.[[PerformFetch]] 设置为 performFetch

  5. loadingPromiserecord.LoadRequestedModules(state)。

    此步骤将递归地加载所有模块传递依赖项。

  6. loadingPromise 完成 时,运行以下步骤

    1. 执行 record.Link()。

      此步骤将递归地调用 Link,用于所有模块的未链接依赖项。

      如果这引发了异常,则捕获它,并将 moduleScript要重新抛出的错误 设置为该异常。

    2. 使用 moduleScript 运行 onComplete

  7. loadingPromise 拒绝 时,运行以下步骤

    1. 如果 state.[[ParseError]] 不为 null,则将 moduleScript要重新抛出的错误 设置为 state.[[ParseError]] 并使用 moduleScript 运行 onComplete

    2. 否则,使用 null 运行 onComplete

      loadingPromise 由于加载错误而被拒绝时,state.[[ParseError]] 为 null。

给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 脚本获取选项 options、一个 环境设置对象 settingsObject、一个 referrer referrer、一个可选的 ModuleRequest 记录 moduleRequest、一个布尔值 isTopLevel、一个算法 onComplete 和一个可选的 执行获取钩子 performFetch获取单个模块脚本,运行这些步骤。 onComplete 必须是一个接受 null(失败)或 模块脚本(成功)的算法。

  1. moduleType 为 "javascript-or-wasm"。

  2. 如果给定 moduleRequest,则将 moduleType 设置为使用给定的 moduleRequest 运行 来自模块请求的模块类型 步骤的结果。

  3. 断言:使用给定的 moduleTypesettingsObject 运行 模块类型是否允许 步骤的结果为 true。否则,我们将不会到达此点,因为在 HostLoadImportedModule获取单个导入的模块脚本 中检查 moduleRequest.[[Attributes]] 时会引发失败。

  4. moduleMapsettingsObject模块映射

  5. 如果 moduleMap[(urlmoduleType)] 为 "fetching",则 并行等待 直到该条目的值发生变化,然后在 网络任务源排队一个任务 以继续执行以下步骤。

  6. 如果 moduleMap[(urlmoduleType)] 存在,则使用 moduleMap[(urlmoduleType)] 运行 onComplete 并返回。

  7. 设置 moduleMap[(urlmoduleType)] 为 "fetching"。

  8. request 为一个新的 请求,其 URLurl模式 为 "cors",referrerreferrer客户端fetchClient

  9. request目标 设置为使用给定的 destinationmoduleType 运行 来自模块类型的获取目标 步骤的结果。

  10. 如果 `destination` 是 "worker"、"sharedworker" 或 "serviceworker",并且 `isTopLevel` 为真,则将 `request` 的 模式 设置为 "same-origin"。

  11. 将 `request` 的 发起者类型 设置为 "script"。

  12. 设置模块脚本请求,给定 `request` 和 `options`。

  13. 如果 performFetch 被给出,则使用 requestisTopLevel 和下面定义的 processResponseConsumeBody 运行 performFetch

    否则,获取 `request`,其中 `processResponseConsumeBody` 设置为 `processResponseConsumeBody`,如下定义。

    在这两种情况下,令给定 响应 `response` 和 null、失败或 字节序列 `bodyBytes` 的 `processResponseConsumeBody` 为以下算法

    response 始终是 CORS-同源

    1. 如果以下任何条件为真

      然后 设置 `moduleMap[(url, moduleType)]` 为 null,运行给定 null 的 `onComplete`,并中止这些步骤。

    2. 令 `mimeType` 为从 response标题列表提取 MIME 类型 的结果。

    3. 令 `moduleScript` 为 null。

    4. 令 `referrerPolicy` 为给定 response解析 `Referrer-Policy` 标题 的结果。 [REFERRERPOLICY]

    5. 如果 `referrerPolicy` 不是空字符串,则将 `options` 的 推荐人策略 设置为 `referrerPolicy`。

    6. 如果 `mimeType` 的 本质 是 "application/wasm" 并且 `moduleType` 是 "javascript-or-wasm",则将 `moduleScript` 设置为给定 `bodyBytes`、`settingsObject`、`response` 的 URL 和 `options` 的 创建 WebAssembly 模块脚本 的结果。

    7. 否则

      1. 令 `sourceText` 为 UTF-8 解码 `bodyBytes` 的结果。

      2. 如果 `mimeType` 是 JavaScript MIME 类型 并且 `moduleType` 是 "javascript-or-wasm",则将 `moduleScript` 设置为给定 `sourceText`、`settingsObject`、`response` 的 URL 和 `options` 的 创建 JavaScript 模块脚本 的结果。

      3. 如果 `mimeType` 的 MIME 类型本质 是 "text/css" 并且 `moduleType` 是 "css",则将 `moduleScript` 设置为给定 `sourceText` 和 `settingsObject` 的 创建 CSS 模块脚本 的结果。

      4. 如果 `mimeType` 是 JSON MIME 类型 并且 `moduleType` 是 "json",则将 `moduleScript` 设置为给定 `sourceText` 和 `settingsObject` 的 创建 JSON 模块脚本 的结果。

    8. 设置 `moduleMap[(url, moduleType)]` 为 `moduleScript`,并运行给定 `moduleScript` 的 `onComplete`。

      有意的是,模块映射 采用 请求 URL 作为键,而 基本 URL 则为 模块脚本 设置为 响应 URL。前者用于消除获取重复项,而后者用于 URL 解析。

为了 获取单个导入的模块脚本,给定一个 URL `url`、一个 环境设置对象 `fetchClient`、一个 目标 `destination`、一个 脚本获取选项 `options`、环境设置对象 `settingsObject`、一个 推荐人 `referrer`、一个 ModuleRequest 记录 `moduleRequest`、一个算法 `onComplete` 和一个可选的 执行获取钩子 `performFetch`,运行这些步骤。`onComplete` 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。

  1. 断言:`moduleRequest.[[Attributes]]` 不包含任何 记录 `entry`,使得 `entry.[[Key]]` 不是 "type",因为我们只在 HostGetSupportedImportAttributes 中请求了 "type" 属性。

  2. 令 `moduleType` 为运行给定 `moduleRequest` 的 模块类型来自模块请求 步骤的结果。

  3. 如果运行给定 `moduleType` 和 `settingsObject` 的 模块类型允许 步骤的结果为 false,则运行给定 null 的 `onComplete`,并返回。

  4. 获取单个模块脚本,给定 `url`、`fetchClient`、`destination`、`options`、`settingsObject`、`referrer`、`moduleRequest`、false 和 `onComplete`。如果给出了 `performFetch`,也将其传递。

8.1.4.3 创建脚本

为了 创建经典脚本,给定一个 字符串 `source`、一个 环境设置对象 `settings`、一个 URL `baseURL`、一个 脚本获取选项 `options`、一个可选的布尔值 `mutedErrors`(默认值为 false)和一个可选的 URL-或-null `sourceURLForWindowScripts`(默认值为 null)

  1. 如果 `mutedErrors` 为真,则将 `baseURL` 设置为 "about:blank"。

    当 `mutedErrors` 为真时,`baseURL` 是脚本的 CORS-跨源 响应url,它不应暴露给 JavaScript。因此,`baseURL` 在此处被清理。

  2. 如果 脚本被禁用 用于 `settings`,则将 `source` 设置为空字符串。

  3. 令 `script` 为一个新的 经典脚本,该算法将随后初始化。

  4. 将 `script` 的 设置对象 设置为 `settings`。

  5. 将 `script` 的 基本 URL 设置为 `baseURL`。

  6. 将 `script` 的 获取选项 设置为 `options`。

  7. 将 `script` 的 静音错误 设置为 `mutedErrors`。

  8. 将 `script` 的 解析错误要重新抛出的错误 设置为 null。

  9. 记录经典脚本创建时间,给定 `script` 和 `sourceURLForWindowScripts`。

  10. 令 `result` 为 ParseScript(`source`,`settings` 的 领域,`script`)。

    将 `script` 作为最后一个参数传递到这里可确保 `result.[[HostDefined]]` 将为 `script`。

  11. 如果 `result` 是一个 列表 错误,则

    1. 将 `script` 的 解析错误 及其 要重新抛出的错误 设置为 `result[0]`。

    2. 返回 script

  12. 将 `script` 的 记录 设置为 `result`。

  13. 返回 script

为了 创建 JavaScript 模块脚本,给定一个 字符串 `source`、一个 环境设置对象 `settings`、一个 URL `baseURL` 和一个 脚本获取选项 `options`

  1. 如果 脚本被禁用 用于 `settings`,则将 `source` 设置为空字符串。

  2. 令 `script` 为一个新的 模块脚本,该算法将随后初始化。

  3. 将 `script` 的 设置对象 设置为 `settings`。

  4. 将 `script` 的 基本 URL 设置为 `baseURL`。

  5. 将 `script` 的 获取选项 设置为 `options`。

  6. 将 `script` 的 解析错误要重新抛出的错误 设置为 null。

  7. 令 `result` 为 ParseModule(`source`,`settings` 的 领域,`script`)。

    将 `script` 作为最后一个参数传递到这里可确保 `result.[[HostDefined]]` 将为 `script`。

  8. 如果 `result` 是一个 列表 错误,则

    1. script解析错误 设置为 result[0]。

    2. 返回 script

  9. script记录 设置为 result

  10. 返回 script

创建一个 WebAssembly 模块脚本,给定一个 字节序列 bodyBytes,一个 环境设置对象 settings,一个 URL baseURL,以及一个 脚本获取选项 options

  1. 如果 脚本被禁用 用于 settings,则将 bodyBytes 设置为字节序列 0x00 0x61 0x73 0x6d 0x01 0x00 0x00 0x00。

    此字节序列对应于一个空的 WebAssembly 模块,它只包含魔数和版本号。

  2. script 是一个新的 模块脚本,该算法随后将对其进行初始化。

  3. script设置对象 设置为 settings

  4. script基本 URL 设置为 baseURL

  5. script获取选项 设置为 options

  6. script解析错误需要重新抛出的错误 设置为 null。

  7. result解析 WebAssembly 模块 的结果,给定 bodyBytessettings领域,以及 script

    将 `script` 作为最后一个参数传递到这里可确保 `result.[[HostDefined]]` 将为 `script`。

  8. 如果前一步抛出了一个错误 error,则

    1. script解析错误 设置为 error

    2. 返回 script

  9. script记录 设置为 result

  10. 返回 script

WebAssembly JavaScript 接口:ESM 集成 指定了 WebAssembly 与 ECMA-262 模块加载集成的钩子。这包括对直接依赖项导入的支持,以及对源阶段导入的支持,该阶段支持虚拟化和多实例化。[WASMESM]

创建一个 CSS 模块脚本,给定一个字符串 source 和一个 环境设置对象 settings

  1. script 是一个新的 模块脚本,该算法随后将对其进行初始化。

  2. script设置对象 设置为 settings

  3. script基本 URL获取选项 设置为 null。

  4. script解析错误需要重新抛出的错误 设置为 null。

  5. sheet 是运行步骤以 创建一个构造的 CSSStyleSheet 的结果,其参数为空字典。

  6. 运行步骤以 同步替换 CSSStyleSheet 的规则,在 sheet 上给定 source

    如果这抛出了异常,则捕获它,将 script解析错误 设置为该异常,并返回 script

    步骤以 同步替换 CSSStyleSheet 的规则 将在 source 包含任何 @import 规则时抛出异常。这是目前的设计,因为关于如何处理 CSS 模块脚本的这些规则还没有达成一致;因此,在达成共识之前,它们完全被阻止。

  7. script记录 设置为 CreateDefaultExportSyntheticModule(sheet) 的结果。

  8. 返回 script

创建一个 JSON 模块脚本,给定一个字符串 source 和一个 环境设置对象 settings

  1. script 是一个新的 模块脚本,该算法随后将对其进行初始化。

  2. script设置对象 设置为 settings

  3. script基本 URL获取选项 设置为 null。

  4. script解析错误需要重新抛出的错误 设置为 null。

  5. resultParseJSONModule(source)。

    如果这抛出了异常,则捕获它,将 script解析错误 设置为该异常,并返回 script

  6. script记录 设置为 result

  7. 返回 script

给定一个 ModuleRequest 记录 moduleRequest模块类型来自模块请求 步骤如下

  1. moduleType 为 "javascript-or-wasm"。

  2. 如果 moduleRequest.[[Attributes]] 具有一个 记录 entry,使得 entry.[[Key]] 是 "type",则

    1. 如果 entry.[[Value]] 是 "javascript-or-wasm",则将 moduleType 设置为 null。

      本规范在内部使用 "javascript-or-wasm" 模块类型来表示 JavaScript 模块脚本WebAssembly 模块脚本,因此需要此步骤来防止模块使用 "javascript-or-wasm" 类型属性导入(一个为 null 的 moduleType 将导致 允许的模块类型 检查失败)。

    2. 否则,将 moduleType 设置为 entry.[[Value]]。

  3. 返回 moduleType

给定一个 字符串 moduleType 和一个 环境设置对象 settings允许的模块类型 步骤如下

  1. 如果 moduleType 不是 "javascript-or-wasm"、"css" 或 "json",则返回 false。

  2. 如果 moduleType 是 "css" 并且 CSSStyleSheet 接口在 settings领域未公开,则返回 false。

  3. 返回 true。

给定一个 目标 defaultDestination 和一个 字符串 moduleType获取目标来自模块类型 步骤如下

  1. 如果 moduleType 是 "json",则返回 "json"。
  2. 如果 moduleType 是 "css",则返回 "style"。
  3. 返回 defaultDestination
8.1.4.4 调用脚本

运行一个经典脚本,给定一个 经典脚本 script 和一个可选的布尔值 rethrow errors(默认值为 false)

  1. settingsscript设置对象

  2. 检查我们是否可以运行脚本,使用 settings。如果这返回 "不运行",则返回 NormalCompletion(empty)。

  3. 记录经典脚本执行开始时间,给定 script

  4. 准备运行脚本,给定 settings

  5. evaluationStatus 为 null。

  6. 如果 script需要重新抛出的错误 不为 null,则将 evaluationStatus 设置为 Completion { [[Type]]: throw, [[Value]]: script需要重新抛出的错误, [[Target]]: empty }。

  7. 否则,将 evaluationStatus 设置为 ScriptEvaluation(script记录)。

    如果 ScriptEvaluation 未完成,因为用户代理 中止了正在运行的脚本,则将 evaluationStatus 保持为 null。

  8. 如果 evaluationStatus 是一个 异常完成,则

    1. 如果 rethrow errors 为 true 并且 script静音错误 为 false,则

      1. 清理运行脚本后的操作,使用 settings

      2. 重新抛出 evaluationStatus.[[Value]]。

    2. 如果 rethrow errors 为 true 并且 script静音错误 为 true,则

      1. 清理运行脚本后的操作,使用 settings

      2. 抛出一个 "NetworkError" DOMException

    3. 否则,rethrow errors 为 false。执行以下步骤

      1. 报告异常,由 evaluationStatus.[[Value]] 提供,用于 script设置对象全局对象

      2. 清理运行脚本后的操作,使用 settings

      3. 返回 evaluationStatus

  9. 清理运行脚本后的操作,使用 settings

  10. 如果 evaluationStatus 是一个正常完成,则返回 evaluationStatus

  11. 如果我们已经到达这一步,evaluationStatus 将保持为 null,因为脚本在评估期间被 过早中止。返回 Completion { [[Type]]: throw, [[Value]]: 新的 "QuotaExceededError" DOMException, [[Target]]: 空 }。

运行模块脚本,给定一个 模块脚本 script 和一个可选的布尔值 preventErrorReporting(默认值为 false)

  1. settingsscript设置对象

  2. 检查我们是否可以运行脚本,使用 settings。如果这返回 "do not run",则返回 一个解析为 undefined 的 Promise。

  3. 记录模块脚本执行开始时间,给定 script

  4. 准备运行脚本,给定 settings

  5. evaluationPromise 为 null。

  6. 如果 script要重新抛出的错误 不为 null,则将 evaluationPromise 设置为 一个被 script要重新抛出的错误 拒绝的 Promise。

  7. 否则

    1. recordscript记录

    2. evaluationPromise 设置为 record.Evaluate()。

      此步骤将递归评估模块的所有依赖项。

      如果 Evaluate 由于用户代理 中止运行脚本 而无法完成,则将 evaluationPromise 设置为 一个被 新的 "QuotaExceededError" DOMException 拒绝的 Promise。

  8. 如果 preventErrorReporting 为 false,则 evaluationPromisereason 拒绝时报告一个异常,该异常由 reasonscript设置对象全局对象 提供。

  9. 清理运行脚本后的操作,使用 settings

  10. 返回 evaluationPromise

使用 环境设置对象 settings 检查我们是否可以运行脚本 的步骤如下。它们返回 "run" 或 "do not run"。

  1. 如果 settings 指定的 全局对象 是一个 Window 对象,其 Document 对象不是 完全活动,则返回 "do not run"。

  2. 如果 脚本被禁用,针对 settings,则返回 "do not run"。

  3. 返回 "run"。

使用 环境设置对象 settings 准备运行脚本 的步骤如下

  1. settings领域执行上下文 推入 JavaScript 执行上下文栈;它现在是 正在运行的 JavaScript 执行上下文

  2. settings 添加到 周围代理事件循环当前正在运行的任务脚本评估环境设置对象集

使用 环境设置对象 settings 清理运行脚本后的操作 的步骤如下

  1. 断言settings领域执行上下文正在运行的 JavaScript 执行上下文

  2. JavaScript 执行上下文栈 中删除 settings领域执行上下文

  3. 如果 JavaScript 执行上下文栈 现在为空,执行微任务检查点。(如果这运行脚本,这些算法将被重新进入调用。)

这些算法不是由一个脚本直接调用另一个脚本来调用的,但它们可以以间接的方式被重新进入调用,例如,如果一个脚本调度了一个事件,并且该事件注册了事件监听器。

正在运行的脚本脚本,位于 正在运行的 JavaScript 执行上下文 的 ScriptOrModule 组件的 [[HostDefined]] 字段中。

8.1.4.5 杀死脚本

虽然 JavaScript 规范没有考虑这种可能性,但有时有必要 中止运行脚本。这会导致任何 ScriptEvaluationSource Text Module RecordEvaluate 调用立即停止,清空 JavaScript 执行上下文栈,而不会触发任何正常机制,如 finally 块。 [JAVASCRIPT]

用户代理可能会对脚本施加资源限制,例如 CPU 配额、内存限制、总执行时间限制或带宽限制。当脚本超出限制时,用户代理可以抛出 "QuotaExceededError" DOMException中止脚本 而不抛出异常,提示用户,或限制脚本执行。

例如,以下脚本永远不会终止。用户代理可以在等待几秒钟后,提示用户要么终止脚本,要么让它继续。

<script>
 while (true) { /* loop */ }
</script>

鼓励用户代理允许用户在脚本提示用户(例如,使用 window.alert() API)或由于脚本的操作(例如,因为脚本超出了时间限制)时,禁用脚本。

如果脚本在执行期间被禁用,则应立即终止脚本。

用户代理可以允许用户专门禁用脚本,仅用于关闭 浏览上下文 的目的。

例如,上面示例中提到的提示还可以向用户提供一种机制,可以完全关闭页面,而无需运行任何 unload 事件处理程序。

8.1.4.6 运行时脚本错误

reportError

在所有当前引擎中支持。

Firefox93+Safari15.4+Chrome95+
Opera?Edge95+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
self.reportError(e)

在给定值 e 的全局对象上调度一个 error 事件,方式与未捕获的异常相同。

要从 JavaScript 值 exception提取错误信息

  1. attributes 为一个空的 映射,按键为 IDL 属性。

  2. attributes[error] 设置为 exception

  3. attributes[message]、attributes[filename]、attributes[lineno] 和 attributes[colno] 设置为从 exception 中派生的 实现定义的 值。

    浏览器实现这里或 JavaScript 规范中未指定的行为,以收集有用的值,包括在异常情况下(例如,eval)。将来,这可能会被更详细地指定。

  4. 返回 attributes

要针对特定 全局对象 global 和可选布尔值 omitError(默认值为 false)报告一个异常 exception,该异常是一个 JavaScript 值

  1. notHandled 为 true。

  2. errorInfo 为从 exception提取错误信息 的结果。

  3. script 为一个 脚本,该脚本以 实现定义的 方式找到,或为 null。这通常应该是 正在运行的脚本(最显著的是在 运行经典脚本 期间)。

    对于不太常见的情况,各个实现尚未就用于确定是否静音错误的脚本使用达成一致的可互操作行为。

  4. 如果 script 是一个 经典脚本script静音错误 为 true,则将 errorInfo[error] 设置为 null,errorInfo[message] 设置为 "Script error.",errorInfo[filename] 设置为空字符串,errorInfo[lineno] 设置为 0,errorInfo[colno] 设置为 0。

  5. 如果 omitError 为 true,则将 errorInfo[error] 设置为 null。

  6. 如果 global 不是 处于错误报告模式,则

    1. global处于错误报告模式 设置为 true。
    2. 如果 global 实现 EventTarget,则将 notHandled 设置为在 global触发一个名为 error 的事件的结果,使用 ErrorEvent,其中 cancelable 属性初始化为 true,其他属性根据 errorInfo 初始化。

      在事件处理程序中返回 true 会根据 事件处理程序处理算法 取消事件。

    3. global处于错误报告模式 设置为 false。

  7. 如果 notHandled 为 true,则

    1. errorInfo[error] 设置为 null。

    2. 如果 global 实现 DedicatedWorkerGlobalScope global 关联的 Worker相关全局对象 上,DOM 操作任务源排队一个全局任务,以执行以下步骤

      1. workerObject 为与 global 关联的 Worker 对象。

      2. notHandled 设置为在 workerObject触发一个名为 error 的事件的结果,使用 ErrorEvent,其中 cancelable 属性初始化为 true,其他属性根据 errorInfo 初始化。

      3. 如果 notHandled 为 true,则 报告 exception,针对 workerObject相关全局对象omitError 设置为 true。

        实际的 exception 值在拥有者领域将不可用,但用户代理仍然会传达足够的信息来设置消息、文件名和其他属性,以及可能向开发者控制台报告。

  8. 否则,用户代理可能会向开发者控制台报告 exception

如果连接 worker 与其 Worker 对象的隐式端口已断开(即如果父 worker 已终止),则用户代理必须假装 Worker 对象没有 error 事件处理程序,并且该 worker 的 onerror 属性为 null,但在其他情况下必须按上述方式执行。

因此,错误报告会一直传播到专用 worker 链,直到到达原始 Document,即使此链中的某些 worker 已终止并被垃圾回收。

此标准的先前修订版定义了 报告异常 的算法。作为 issue #958 的一部分,该算法已被 报告异常 替代,该算法的行为不同并接受不同的输入。 Issue #10516 跟踪更新规范生态系统。


reportError(e) 方法的步骤是 报告异常 e,针对 this

尚不清楚是否 静音 在这里适用。在 Chrome 和 Safari 中,它是静音的,但在 Firefox 中则不是。另请参见 issue #958


ErrorEvent

在所有当前引擎中支持。

Firefox27+Safari6+Chrome10+
Opera11+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android11+

ErrorEvent 接口定义如下

[Exposed=*]
interface ErrorEvent : Event {
  constructor(DOMString type, optional ErrorEventInit eventInitDict = {});

  readonly attribute DOMString message;
  readonly attribute USVString filename;
  readonly attribute unsigned long lineno;
  readonly attribute unsigned long colno;
  readonly attribute any error;
};

dictionary ErrorEventInit : EventInit {
  DOMString message = "";
  USVString filename = "";
  unsigned long lineno = 0;
  unsigned long colno = 0;
  any error;
};

message 属性必须返回其初始化的值。它表示错误消息。

filename 属性必须返回其初始化的值。它表示发生错误的脚本的 URL

lineno 属性必须返回其初始化的值。它表示脚本中发生错误的行号。

colno 属性必须返回其初始化的值。它表示脚本中发生错误的列号。

error 属性必须返回其初始化的值。它最初必须初始化为 undefined。在适当的地方,它被设置为表示错误的对象(例如,在未捕获异常的情况下,为异常对象)。

8.1.4.7 未处理的 Promise 拒绝

Window/rejectionhandled_event

在所有当前引擎中支持。

Firefox69+Safari11+Chrome49+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android?

除了同步 运行时脚本错误 外,脚本还会遇到异步 Promise 拒绝,通过 unhandledrejectionrejectionhandled 事件进行跟踪。通过 HostPromiseRejectionTracker 抽象操作来跟踪这些拒绝,但它们的报告在此处定义。

通知关于被拒绝的 Promise,给定 全局对象 global

  1. listglobal即将被通知的被拒绝的 Promise 列表克隆

  2. 如果 list 为空,则返回。

  3. 清空 global即将被通知的被拒绝的 Promise 列表

  4. global 上,DOM 操作任务源排队一个全局任务,以执行以下步骤

    1. 对于 list 中的每个 Promise p

      1. 如果 p.[[PromiseIsHandled]] 为 true,则 继续

      2. notCanceled 为在 global触发一个名为 unhandledrejection 的事件的结果,使用 PromiseRejectionEvent,其中 cancelable 属性初始化为 true,promise 属性初始化为 preason 属性初始化为 p.[[PromiseResult]]。

      3. 如果 notCanceled 为 true,则用户代理可能会向开发者控制台报告 p.[[PromiseResult]]。

      4. 如果 p.[[PromiseIsHandled]] 为 false,则 p 追加global未处理的被拒绝的 Promise 弱集合

PromiseRejectionEvent

在所有当前引擎中支持。

Firefox69+Safari11+Chrome49+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android?

PromiseRejectionEvent 接口定义如下

[Exposed=*]
interface PromiseRejectionEvent : Event {
  constructor(DOMString type, PromiseRejectionEventInit eventInitDict);

  readonly attribute object promise;
  readonly attribute any reason;
};

dictionary PromiseRejectionEventInit : EventInit {
  required object promise;
  any reason;
};

PromiseRejectionEvent/promise

在所有当前引擎中支持。

Firefox69+Safari11+Chrome49+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android?

promise 属性必须返回其初始化的值。它表示此通知所针对的 Promise。

由于 Web IDL 针对 Promise<T> 类型的转换规则始终将输入包装到一个新的 Promise 中,因此 promise 属性的类型为 object,更适合表示对原始 Promise 对象的不透明句柄。

PromiseRejectionEvent/reason

在所有当前引擎中支持。

Firefox69+Safari11+Chrome49+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android?

reason 属性必须返回其初始化的值。它表示 promise 的拒绝原因。

8.1.4.8 导入映射解析结果

一个 导入映射解析结果 是一个类似于 脚本结构体,也可以存储在 script 元素的 结果 中,但对于其他目的不计入 脚本。它具有以下

一个 导入映射
一个 导入映射 或 null。
一个 要重新抛出的错误
一个 JavaScript 值,表示一个错误,它将阻止使用此导入映射,当不为 null 时。

创建导入映射解析结果,给定一个 字符串 input 和一个 URL baseURL

  1. result 为一个 导入映射解析结果,其 导入映射 为 null,其 要重新抛出的错误 为 null。

  2. 给定 inputbaseURL 解析导入映射字符串,捕获任何异常。如果这抛出了异常,则将 result要重新抛出的错误 设置为该异常。否则,将 result导入映射 设置为返回值。

  3. 返回 result

注册导入映射,给定一个 Window global 和一个 导入映射解析结果 result

  1. 如果 result要重新抛出的错误 不为 null,则 报告异常,由 result要重新抛出的错误global 提供,然后返回。

  2. 断言global导入映射 是一个 空导入映射

  3. global导入映射 设置为 result导入映射

8.1.5 模块标识符解析

8.1.5.1 解析算法

解析模块标识符 算法是将模块标识符字符串转换为 URL 的主要入口点。当没有涉及 导入映射 时,它相对简单,并且简化为 解析 URL 样式的模块标识符

当存在一个非空的 导入映射 时,行为更加复杂。它检查所有适用 模块标识符映射 中的候选条目,从最特定到最不特定的 范围(回退到顶级无范围 导入),以及从最特定到最不特定的前缀。对于每个候选条目,解析导入匹配 算法将给出以下结果

最后,如果通过任何候选 模块标识符映射 都没有找到成功的解析,解析模块标识符 将抛出一个异常。因此,结果始终是一个 URL 或一个抛出的异常。

解析模块标识符,给定一个 script-或-null referringScript 和一个 字符串 specifier

  1. settingsObjectbaseURL 为 null。

  2. 如果 referringScript 不为 null,则

    1. settingsObject 设置为 referringScript设置对象

    2. baseURL 设置为 referringScript基本 URL

  3. 否则

    1. 断言:存在一个 当前设置对象

    2. settingsObject 设置为 当前设置对象

    3. baseURL 设置为 settingsObjectAPI 基本 URL

  4. importMap 为一个 空导入映射

  5. 如果 settingsObject全局对象 实现 Window,则将 importMap 设置为 settingsObject全局对象导入映射

  6. baseURLStringbaseURL序列化

  7. asURL 为给定 specifierbaseURL解析 URL 样式的模块标识符 的结果。

  8. normalizedSpecifierasURL序列化,如果 asURL 不为 null;否则,specifier

  9. 对于每个 scopePrefixscopeImportsimportMap范围

    1. 如果 scopePrefixbaseURLString,或者如果 scopePrefix 以 U+002F (/) 结尾,并且 scopePrefixbaseURLString代码单元前缀,则

      1. scopeImportsMatch 为给定 normalizedSpecifierasURLscopeImports解析导入匹配 的结果。

      2. 如果 scopeImportsMatch 不为 null,则返回 scopeImportsMatch

  10. topLevelImportsMatch 为给定 normalizedSpecifierasURLimportMap导入解析导入匹配 的结果。

  11. 如果 topLevelImportsMatch 不为 null,则返回 topLevelImportsMatch

  12. 此时,specifier 没有被 importMap 重新映射到任何内容,但它可能能够被转换为 URL。

    如果 asURL 不为 null,则返回 asURL

  13. 抛出一个 TypeError,指示 specifier 是一个裸标识符,但没有被 importMap 重新映射到任何内容。

解析导入匹配,给定一个 字符串 normalizedSpecifier、一个 URL-或-null asURL 和一个 模块标识符映射 specifierMap

  1. 对于每个 specifierKeyresolutionResultspecifierMap

    1. 如果 specifierKeynormalizedSpecifier,则

      1. 如果 resolutionResult 为 null,则抛出一个 TypeError,指示 specifierKey 的解析被 null 条目阻止。

        这将终止整个 解析模块标识符 算法,没有任何进一步的回退。

      2. 断言resolutionResult 是一个 URL

      3. 返回 resolutionResult

    2. 如果以下所有条件都为真

      • specifierKey 以 U+002F (/) 结尾;

      • specifierKeynormalizedSpecifier代码单元前缀;并且

      • 要么 asURL 为 null,要么 asURL 是特殊的

      1. 如果 resolutionResult 为 null,则抛出一个 TypeError,指示 specifierKey 的解析被 null 条目阻止。

        这将终止整个 解析模块标识符 算法,没有任何进一步的回退。

      2. 断言resolutionResult 是一个 URL

      3. afterPrefixnormalizedSpecifier 中初始 specifierKey 前缀后的部分。

      4. 断言resolutionResult序列化,以 U+002F (/) 结尾,如 解析 期间强制执行的那样。

      5. urlafterPrefix 使用 resolutionResultURL 解析 的结果。

      6. 如果 url 为失败,则抛出一个 TypeError,指示 normalizedSpecifier 的解析被阻止,因为 afterPrefix 部分无法相对于 specifierKey 前缀映射到的 resolutionResult 进行 URL 解析。

        这将终止整个 解析模块标识符 算法,没有任何进一步的回退。

      7. 断言url 是一个 URL

      8. 如果resolutionResult序列化不是url序列化代码单元前缀,则抛出一个TypeError,指示normalizedSpecifier的解析由于回溯到其前缀specifierKey之上而被阻止。

        这将终止整个解析模块说明符算法,不再进行任何回退。

      9. 返回url

  2. 返回null。

    如果可能的话,解析模块说明符算法将回退到不太具体的范围,或回退到“imports”。

为了解析类似 URL 的模块说明符,给定一个字符串specifier和一个URLbaseURL

  1. 如果specifier/”,“./”或“../”开头,那么

    1. url成为URL 解析specifierbaseURL的结果。

    2. 如果url失败,则返回null。

      这可能发生的一种情况是,如果specifier是“../foo”,而baseURLdata: URL。

    3. 返回url

    这包括specifier//”开头的情况,即方案相关的 URL。因此,url最终可能与baseURL具有不同的主机

  2. url成为URL 解析specifier(没有基本 URL)的结果。

  3. 如果url失败,则返回null。

  4. 返回url

8.1.5.2 导入映射

一个导入映射允许控制模块说明符解析。导入映射通过内联script元素传递,这些元素的type属性设置为“importmap”,并且其子文本内容包含导入映射的 JSON 表示形式。

每个Document只处理一个导入映射。在看到第一个导入映射后,将忽略其他导入映射,并且它们对应的script元素将生成error事件。类似地,一旦任何模块被导入(例如,通过import()表达式或script元素,其type属性设置为“module”),将忽略进一步的导入映射。

这些限制以及对外部导入映射的支持缺乏,是为了使该功能的初始版本保持简单。随着实现者带宽的允许,它们可能会随着时间的推移而解除。

导入映射的最简单用法是全局重新映射一个裸模块说明符

{
  "imports": {
    "moment": "/node_modules/moment/src/moment.js"
  }
}

这使得像import moment from "moment";这样的语句能够工作,并在/node_modules/moment/src/moment.js URL 处获取并评估 JavaScript 模块。

导入映射可以通过使用尾部斜杠来重新映射一类模块说明符到一类 URL,如下所示

{
  "imports": {
    "moment/": "/node_modules/moment/src/"
  }
}

这使得像import localeData from "moment/locale/zh-cn.js";这样的语句能够工作,并在/node_modules/moment/src/locale/zh-cn.js URL 处获取并评估 JavaScript 模块。这种尾部斜杠映射通常与裸说明符映射相结合,例如

{
  "imports": {
    "moment": "/node_modules/moment/src/moment.js",
    "moment/": "/node_modules/moment/src/"
  }
}

这样,“moment”指定的“主模块”和由诸如“moment/locale/zh-cn.js”之类的路径指定的“子模块”都可用。

裸说明符不是导入映射可以重新映射的唯一类型的模块说明符。“类似 URL”的说明符,即那些可解析为绝对 URL 或以“/”,“./”或“../”开头的说明符,也可以重新映射

{
  "imports": {
    "https://cdn.example.com/vue/dist/vue.runtime.esm.js": "/node_modules/vue/dist/vue.runtime.esm.js",
    "/js/app.mjs": "/js/app-8e0d62a03.mjs",
    "../helpers/": "https://cdn.example/helpers/"
  }
}

请注意,要重新映射的 URL 以及要映射到的 URL 可以指定为绝对 URL,也可以指定为以“/”,“./”或“../”开头的相对 URL。(它们不能指定为没有这些起始符号的相对 URL,因为这些符号有助于区分裸模块说明符。)还要注意,尾部斜杠映射在此上下文中也能正常工作。

这种重新映射操作在后规范化 URL 上进行,并且不需要导入映射键中提供的文字字符串与导入的模块说明符之间匹配。例如,如果这个导入映射包含在https://example.com/app.html上,那么不仅import "/js/app.mjs"会被重新映射,而且import "./js/app.mjs"import "./foo/../js/app.mjs"也会被重新映射。

所有前面的示例都通过使用导入映射中的顶级“imports”键来全局重新映射模块说明符。顶级“scopes”键可用于提供局部重新映射,这些重新映射仅在引用模块与特定 URL 前缀匹配时才适用。例如

{
  "scopes": {
    "/a/" : {
      "moment": "/node_modules/moment/src/moment.js"
    },
    "/b/" : {
      "moment": "https://cdn.example.com/moment/src/moment.js"
    }
  }
}

使用这个导入映射,语句import "moment"将具有不同的含义,具体取决于哪个引用脚本包含该语句

范围的典型用法是允许多个版本的“相同”模块存在于 Web 应用程序中,模块图的一部分导入一个版本,而另一部分导入另一个版本。

范围可以相互重叠,也可以与全局“imports”说明符映射重叠。在解析时,将按从最具体到最不具体的顺序咨询范围,其中具体性是通过使用代码单元小于操作对范围进行排序来衡量的。因此,例如,“/scope2/scope3/”被视为比“/scope2/”更具体,而“/scope2/”被视为比顶级(无范围)映射更具体。

以下导入映射说明了这一点

{
  "imports": {
    "a": "/a-1.mjs",
    "b": "/b-1.mjs",
    "c": "/c-1.mjs"
  },
  "scopes": {
    "/scope2/": {
      "a": "/a-2.mjs"
    },
    "/scope2/scope3/": {
      "b": "/b-3.mjs"
    }
  }
}

这导致以下解析(为了简洁起见,使用相对 URL)

说明符
"a""b""c"
引用程序/scope1/r.mjs /a-1.mjs /b-1.mjs /c-1.mjs
/scope2/r.mjs /a-2.mjs /b-1.mjs /c-1.mjs
/scope2/scope3/r.mjs /a-2.mjs /b-3.mjs /c-1.mjs

导入映射还可以用于为模块提供完整性元数据,这些元数据将在子资源完整性检查中使用。 [SRI]

以下导入映射说明了这一点

{
  "imports": {
    "a": "/a-1.mjs",
    "b": "/b-1.mjs",
    "c": "/c-1.mjs"
  },
  "integrity": {
    "/a-1.mjs": "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7",
    "/d-1.mjs": "sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk"
  }
}

上面的示例提供了要对模块/a-1.mjs/d-1.mjs实施的完整性元数据,即使后者在映射中未定义为导入。


表示导入映射script元素的子文本内容必须符合以下导入映射创作要求

一个有效的模块说明符映射是一个满足以下要求的 JSON 对象

8.1.5.3 导入映射处理模型

正式地说,导入映射是一个具有三个项目结构

一个模块说明符映射是一个有序映射,其字符串,其URL或null。

一个 模块完整性映射 是一个 有序映射,其 URL,其 字符串,这些字符串将用作 完整性元数据

一个 空导入映射 是一个 导入映射,其 导入范围 都是空映射。


每个 Window 都有一个 导入映射,最初是一个 空导入映射

每个 Window 都有一个 允许导入映射 布尔值,最初为 true。

禁止进一步导入映射,给定一个 环境设置对象 settingsObject

  1. globalsettingsObject全局对象

  2. 如果 global 没有实现 Window,则返回。

  3. global允许导入映射 设置为 false。

目前,一旦任何模块加载开始,或者一旦加载了单个导入映射,导入映射就会被禁止。这些限制可能会在未来的规范修订中被解除。


解析导入映射字符串,给定一个 字符串 input 和一个 URL baseURL

  1. parsed 是给定 input将 JSON 字符串解析为 Infra 值 的结果。

  2. 如果 parsed 不是一个 有序映射,则抛出一个 TypeError,表明顶层值需要是 JSON 对象。

  3. sortedAndNormalizedImports 是一个空的 有序映射

  4. 如果 parsed["imports"] 存在,则

    1. 如果 parsed["imports"] 不是一个 有序映射,则抛出一个 TypeError,表明 "imports" 顶层键的值需要是 JSON 对象。

    2. sortedAndNormalizedImports 设置为给定 parsed["imports"] 和 baseURL对模块说明符映射进行排序和规范化 的结果。

  5. sortedAndNormalizedScopes 是一个空的 有序映射

  6. 如果 parsed["scopes"] 存在,则

    1. 如果 parsed["scopes"] 不是一个 有序映射,则抛出一个 TypeError,表明 "scopes" 顶层键的值需要是 JSON 对象。

    2. sortedAndNormalizedScopes 设置为给定 parsed["scopes"] 和 baseURL对范围进行排序和规范化 的结果。

  7. normalizedIntegrity 是一个空的 有序映射

  8. 如果 parsed["integrity"] 存在,则

    1. 如果 parsed["integrity"] 不是一个 有序映射,则抛出一个 TypeError,表明 "integrity" 顶层键的值需要是 JSON 对象。

    2. normalizedIntegrity 设置为给定 parsed["integrity"] 和 baseURL对模块完整性映射进行规范化 的结果。

  9. 如果 parsed 包含 除了 "imports"、"scopes" 或 "integrity" 之外的任何项目,则用户代理应该 向控制台报告警告,表明在导入映射中存在无效的顶层键。

    这可以帮助检测拼写错误。这不是错误,因为这会阻止将来任何扩展以向后兼容的方式添加。

  10. 返回一个 导入映射,其 导入sortedAndNormalizedImports,其 范围sortedAndNormalizedScopes,其 完整性normalizedIntegrity

从这个解析算法得出的 导入映射 是高度规范化的。例如,给定一个基本 URL https://example.com/base/page.html,输入

{
  "imports": {
    "/app/helper": "node_modules/helper/index.mjs",
    "lodash": "/node_modules/lodash-es/lodash.js"
  }
}

将生成一个 导入映射,其 导入

«[
  "https://example.com/app/helper" → https://example.com/base/node_modules/helper/index.mjs
  "lodash" → https://example.com/node_modules/lodash-es/lodash.js
]»

并且(尽管输入字符串中没有内容)为空的 有序映射,作为其 范围

对模块说明符映射进行排序和规范化,给定一个 有序映射 originalMap 和一个 URL baseURL

  1. normalized 是一个空的 有序映射

  2. 对于每个 specifierKeyvalueoriginalMap

    1. normalizedSpecifierKey 是给定 specifierKeybaseURL对说明符键进行规范化 的结果。

    2. 如果 normalizedSpecifierKey 为 null,则 继续

    3. 如果 value 不是一个 字符串,则

      1. 用户代理可以 向控制台报告警告,表明地址需要是字符串。

      2. normalized[normalizedSpecifierKey] 设置为 null。

      3. 继续.

    4. addressURL 是给定 valuebaseURL解析类似 URL 的模块说明符 的结果。

    5. 如果 addressURL 为 null,则

      1. 用户代理可以 向控制台报告警告,表明地址无效。

      2. normalized[normalizedSpecifierKey] 设置为 null。

      3. 继续.

    6. 如果 specifierKey 以 U+002F (/) 结尾,并且 addressURL序列化 不以 U+002F (/) 结尾,则

      1. 用户代理可以 向控制台报告警告,表明为说明符键 specifierKey 提供了无效的地址;由于 specifierKey 以斜杠结尾,因此地址也需要以斜杠结尾。

      2. normalized[normalizedSpecifierKey] 设置为 null。

      3. 继续.

    7. normalized[normalizedSpecifierKey] 设置为 addressURL

  3. 返回 按降序排序 normalized 的结果,如果条目 a 按代码单元小于 条目 b,则条目 a 小于条目 b

对范围进行排序和规范化,给定一个 有序映射 originalMap 和一个 URL baseURL

  1. normalized 是一个空的 有序映射

  2. 对于每个 scopePrefixpotentialSpecifierMaporiginalMap

    1. 如果 potentialSpecifierMap 不是一个 有序映射,则抛出一个 TypeError,表明具有前缀 scopePrefix 的范围的值需要是 JSON 对象。

    2. scopePrefixURL 是使用 baseURL 解析 URL scopePrefix 的结果。

    3. 如果 scopePrefixURL 为失败,则

      1. 用户代理可以 向控制台报告警告,表明范围前缀 URL 不可解析。

      2. 继续.

    4. normalizedScopePrefixscopePrefixURL序列化

    5. normalized[normalizedScopePrefix] 设置为给定 potentialSpecifierMapbaseURL对模块说明符映射进行排序和规范化 的结果。

  3. 返回 按降序排序 normalized 的结果,如果条目 a 按代码单元小于 条目 b,则条目 a 小于条目 b

在上面两个算法中,按降序排序键和作用域的效果是将“foo/bar/”放在“foo/”之前。这反过来在模块标识符解析期间使“foo/bar/”的优先级高于“foo/”。

规范化模块完整性映射,给定一个有序映射originalMap

  1. normalized 为一个空的有序映射

  2. 对于originalMap的每个keyvalue

    1. resolvedURL 为给定keybaseURL解析 URL 样式模块标识符的结果。

      与“imports”不同,完整性映射的键被视为 URL,而不是模块标识符。但是,我们使用解析 URL 样式模块标识符算法来禁止“裸”相对 URL(例如 foo),这些 URL 可能被误认为是模块标识符。

    2. 如果resolvedURL 为空,则

      1. 用户代理可以向控制台报告警告,表明该键解析失败。

      2. 继续.

    3. 如果value 不是一个字符串,则

      1. 用户代理可以向控制台报告警告,表明完整性元数据值需要是字符串

      2. 继续.

    4. normalized[resolvedURL] 设置为value

  3. 返回normalized

规范化标识符键,给定一个字符串specifierKey 和一个URLbaseURL

  1. 如果specifierKey 为空字符串,则

    1. 用户代理可以向控制台报告警告,表明标识符键不能是空字符串。

    2. 返回null。

  2. url 为给定specifierKeybaseURL解析 URL 样式模块标识符的结果。

  3. 如果url 不为空,则返回url序列化

  4. 返回specifierKey

8.1.6 JavaScript 规范主机钩子

JavaScript 规范包含许多实现定义的抽象操作,这些操作会根据主机环境而有所不同。本节为用户代理主机定义了这些操作。

8.1.6.1 HostEnsureCanAddPrivateElement(O)

JavaScript 包含一个实现定义的HostEnsureCanAddPrivateElement(O) 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]

  1. 如果O 是一个WindowProxy 对象,或者实现 Location,则返回 Completion { [[Type]]: throw, [[Value]]: 一个新的 TypeError }。

  2. 返回NormalCompletion(unused)。

JavaScript 私有字段可以应用于任意对象。由于这可能会为特别奇特的宿主对象极大地复杂化实现,因此 JavaScript 语言规范提供了此钩子,允许宿主拒绝符合宿主定义标准的对象上的私有字段。在 HTML 的情况下,WindowProxyLocation 具有复杂的语义 - 特别是在导航和安全性方面 - 这使得私有字段语义的实现具有挑战性,因此我们的实现只是拒绝这些对象。

8.1.6.2 HostEnsureCanCompileStrings(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg)

JavaScript 包含一个实现定义的HostEnsureCanCompileStrings 抽象操作,由 动态代码品牌检查 提案重新定义。用户代理必须使用以下实现:[JAVASCRIPT] [JSDYNAMICCODEBRANDCHECKS]

  1. 执行 ? EnsureCSPDoesNotBlockStringCompilation(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg)。 [CSP]

8.1.6.3 HostGetCodeForEval(argument)

动态代码品牌检查 提案包含一个实现定义的HostGetCodeForEval(argument) 抽象操作。用户代理必须使用以下实现:[JSDYNAMICCODEBRANDCHECKS]

  1. 如果argument 是一个TrustedScript 对象,则返回argument数据

  2. 否则,返回无代码。

8.1.6.4 HostPromiseRejectionTracker(promise, operation)

JavaScript 包含一个实现定义的HostPromiseRejectionTracker(promise, operation) 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]

  1. script正在运行的脚本

  2. 如果script 是一个经典脚本 并且script静音错误 为 true,则返回。

  3. settingsObject当前设置对象

  4. 如果script 不为空,则将settingsObject 设置为script设置对象

  5. globalsettingsObject全局对象

  6. 如果operation 为“reject”,则

    1. promise 追加到global即将通知的拒绝承诺列表

  7. 如果operation 为“handle”,则

    1. 如果global即将通知的拒绝承诺列表包含promise,则从该列表中删除promise 然后返回。

    2. 如果global未完成的拒绝承诺弱集包含promise,则返回。

    3. global未完成的拒绝承诺弱集删除promise

    4. DOM 操作任务源排队一个全局任务,给定global,以global触发一个名为rejectionhandled 的事件,使用PromiseRejectionEvent,其中promise 属性初始化为promise,而reason 属性初始化为promise.[[PromiseResult]]。

8.1.6.5 HostSystemUTCEpochNanoseconds(global)

Temporal 提案包含一个实现定义的HostSystemUTCEpochNanoseconds 抽象操作。用户代理必须使用以下实现:[JSTEMPORAL]

  1. settingsObjectglobal相关设置对象

  2. timesettingsObject当前墙上时间

  3. ns 为从Unix 纪元time 的纳秒数,四舍五入到最接近的整数。

  4. 返回ns 钳位到nsMinInstantnsMaxInstant 之间的结果。

8.1.6.6 与工作相关的宿主钩子

Reference/Global_Objects/Promise#Incumbent_settings_object_tracking

仅在一个引擎中支持。

Firefox50+SafariChrome
Opera?Edge
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

JavaScript 规范定义了工作,这些工作由宿主调度和稍后运行,以及 JobCallback 记录,它们封装了作为工作的一部分调用的 JavaScript 函数。JavaScript 规范包含许多 实现定义的 抽象操作,允许宿主定义如何调度工作以及如何处理 JobCallbacks。HTML 使用这些抽象操作来 跟踪 现任设置对象 在 promises 和 FinalizationRegistry 回调中,方法是保存和恢复 现任设置对象JavaScript 执行上下文 用于 活动脚本 在 JobCallbacks 中。本节为用户代理宿主定义它们。

8.1.6.6.1 HostCallJobCallback(callback, V, argumentsList)

JavaScript 包含一个 实现定义的 HostCallJobCallback(callback, V, argumentsList) 抽象操作,允许宿主在从任务内部调用 JavaScript 回调时恢复状态。用户代理必须使用以下实现:[JAVASCRIPT]

  1. 现任设置callback.[[HostDefined]].[[IncumbentSettings]]。

  2. 脚本执行上下文callback.[[HostDefined]].[[ActiveScriptContext]]。

  3. 准备运行回调 使用 现任设置

    这会影响 现任 回调运行时的概念。

  4. 如果 脚本执行上下文 不是 null,则 脚本执行上下文 推入 JavaScript 执行上下文堆栈 中。

    这会影响 活动脚本 回调运行时的概念。

  5. resultCall(callback.[[Callback]], V, argumentsList)。

  6. 如果 脚本执行上下文 不是 null,则 弹出 脚本执行上下文JavaScript 执行上下文堆栈 中。

  7. 清理运行回调后的操作 使用 现任设置

  8. 返回 result

8.1.6.6.2 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry)

JavaScript 能够使用 FinalizationRegistry 对象注册对象,以便在发现它们被垃圾收集时调度清理操作。JavaScript 规范包含一个 实现定义的 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry) 抽象操作来调度清理操作。

清理工作的时机和发生是 实现定义的 在 JavaScript 规范中。用户代理在何时以及是否对对象进行垃圾回收方面可能有所不同,这会影响 WeakRef.prototype.deref() 方法的值是否为 undefined,以及 FinalizationRegistry 清理回调是否发生。在流行的网络浏览器中,有众所周知的案例,这些案例中的对象无法被 JavaScript 访问,但它们会无限期地被垃圾收集器保留。HTML 在 执行微任务检查点 算法中清除保持活动的 WeakRef 对象。作者最好不要依赖垃圾收集实现的时机细节。

清理操作不会在同步 JavaScript 执行中交错进行,而是在排队的 任务 中发生。用户代理必须使用以下实现:[JAVASCRIPT]

  1. globalfinalizationRegistry.[[Realm]] 的 全局对象

  2. 在全局任务队列中排队 在给定的 globalJavaScript 引擎任务源 上执行以下步骤

    1. entryfinalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]] 的 环境设置对象

    2. 检查我们是否可以运行脚本 使用 entry。如果这返回“不运行”,则返回。

    3. 准备运行脚本 使用 entry

      这会影响 entry 清理回调运行时的概念。

    4. result 为执行 CleanupFinalizationRegistry(finalizationRegistry) 的结果。

    5. 清理运行脚本后的操作 使用 entry

    6. 如果 result 是一个 异常完成,则 报告异常result.[[Value]] 给出的 global

8.1.6.6.3 HostEnqueueGenericJob(job, realm)

JavaScript 包含一个 实现定义的 HostEnqueueGenericJob(job, realm) 抽象操作,在特定领域执行通用工作(例如,解析由 Atomics.waitAsync 生成的 promises)。用户代理必须使用以下实现:[JAVASCRIPT]

  1. globalrealm全局对象

  2. 在全局任务队列中排队 在给定的 globalJavaScript 引擎任务源 上执行 job()。

8.1.6.6.4 HostEnqueuePromiseJob(job, realm)

JavaScript 包含一个 实现定义的 HostEnqueuePromiseJob(job, realm) 抽象操作,用于调度与 Promise 相关的操作。HTML 在微任务队列中调度这些操作。用户代理必须使用以下实现:[JAVASCRIPT]

  1. 如果 realm 不是 null,则令 job 设置realm设置对象。否则,令 job 设置 为 null。

    如果 realm 不是 null,它就是将要运行的作者代码的 领域。当 jobNewPromiseReactionJob 返回时,它是 promise 的处理程序函数的领域。当 jobNewPromiseResolveThenableJob 返回时,它是 then 函数的领域。

    如果 realm 为 null,则要么没有作者代码会运行,要么作者代码保证会抛出异常。对于前者,作者可能没有传递要运行的代码,例如在 promise.then(null, null) 中。对于后者,这是因为传递了撤销的代理。在这两种情况下,所有原本会使用 job 设置 的后续步骤都将跳过。

    NewPromiseResolveThenableJobNewPromiseReactionJob 似乎都为撤销的代理提供非 null 领域(当前领域记录)。可以更新以前的文本以反映这一点。

  2. 在微任务队列中排队 执行以下步骤

    1. 如果 job 设置 不是 null,则 检查我们是否可以运行脚本 使用 job 设置。如果这返回“不运行”,则返回。

    2. 如果 job 设置 不是 null,则 准备运行脚本 使用 job 设置

      这会影响 entry 工作运行时的概念。

    3. resultjob()。

      job 是由 NewPromiseReactionJobNewPromiseResolveThenableJob 返回的 抽象闭包。当 jobNewPromiseReactionJob 返回时,promise 的处理程序函数;而当 jobNewPromiseResolveThenableJob 返回时,则为 then 函数。这些函数都包装在 JobCallback 记录 中。HTML 将 当前设置对象 和一个 JavaScript 执行上下文 保存到 HostMakeJobCallback 中的 活动脚本,并在 HostCallJobCallback 中恢复它们。

    4. 如果 job 设置 不为 null,则使用 job 设置 进行 运行脚本后的清理

    5. 如果 result 是一个 非正常完成,则针对 realm全局对象,使用 result.[[Value]] 报告异常

      存在一个非常棘手的情况,即 HostEnqueuePromiseJob 被调用时 realm 为 null(例如,因为 Promise.prototype.then 被调用时处理程序为 null),但 job 也会非正常返回(因为 promise 功能的 resolve 或 reject 处理程序抛出了异常,可能是因为这是一个 Promise 的子类,它接受提供的函数并将它们包装在抛出异常的函数中,然后将它们传递给传递给 Promise 超类构造函数的函数。在这种情况下,应该使用哪个全局对象?考虑到当前 realm 在每个步骤都可能不同,例如使用来自另一个 realm 的 Promise 构造函数或 Promise.prototype.then?请参见 问题 #10526

8.1.6.6.5 HostEnqueueTimeoutJob(job, realm, milliseconds)

JavaScript 包含一个 实现定义的 HostEnqueueTimeoutJob(job, milliseconds) 抽象操作,用于在超时后调度一个操作。HTML 使用 在超时后运行步骤 来调度这些操作。用户代理必须使用以下实现:[JAVASCRIPT]

  1. globalrealm全局对象

  2. timeoutStep 为一个算法步骤,该步骤 在全局任务源上排队一个全局任务,该全局任务源由 global 提供,以执行 job()。

  3. 使用 global、"JavaScript"、millisecondstimeoutStep 进行 在超时后运行步骤

8.1.6.6.6 HostMakeJobCallback(callable)

JavaScript 包含一个 实现定义的 HostMakeJobCallback(callable) 抽象操作,用于让主机将状态附加到从 任务 内部调用的 JavaScript 回调。用户代理必须使用以下实现:[JAVASCRIPT]

  1. 当前设置当前设置对象

  2. 活动脚本活动脚本

  3. 脚本执行上下文 为 null。

  4. 如果 活动脚本 不为 null,则将 脚本执行上下文 设置为一个新的 JavaScript 执行上下文,其 Function 字段设置为 null,其 Realm 字段设置为 活动脚本设置对象realm,其 ScriptOrModule 字段设置为 活动脚本记录

    如下所示,这用于将当前 活动脚本 传播到调用 job 回调的时间。

    活动脚本 不为 null 时,将它保存起来很有用,例如以下情况:

    Promise.resolve('import(`./example.mjs`)').then(eval);

    如果没有此步骤(以及在 HostCallJobCallback 中使用它的步骤),当评估 import() 表达式时,就不会有 活动脚本,因为 eval() 是一个内置函数,它不源于任何特定的 脚本

    有了此步骤,活动脚本将从上面的代码传播到 job 中,从而允许 import() 正确地使用原始脚本的 基本 URL

    如果用户单击以下按钮,则 活动脚本 可能为 null:

    <button onclick="Promise.resolve('import(`./example.mjs`)').then(eval)">Click me</button>

    在这种情况下,事件处理程序 的 JavaScript 函数将由 获取事件处理程序的当前值 算法创建,该算法创建一个具有 null [[ScriptOrModule]] 值的函数。因此,当 promise 机制调用 HostMakeJobCallback 时,将没有 活动脚本 传递。

    因此,这意味着当评估 import() 表达式时,仍然没有 活动脚本。幸运的是,我们的 HostLoadImportedModule 实现通过回退到使用 当前设置对象API 基本 URL 来处理这种情况。

  5. 返回 JobCallback 记录 { [[Callback]]: callable, [[HostDefined]]: { [[IncumbentSettings]]: 当前设置, [[ActiveScriptContext]]: 脚本执行上下文 } }。

8.1.6.7 与模块相关的宿主钩子

JavaScript 规范定义了模块的语法,以及它们处理模型中一些与主机无关的部分。本规范定义了它们处理模型的其余部分:模块系统是如何引导的,通过 script 元素(其 type 属性设置为 "module"),以及模块是如何被获取、解析和执行的。 [JAVASCRIPT]

虽然 JavaScript 规范在 "脚本" 和 "模块" 之间进行区分,但本规范通常使用 传统脚本模块脚本 进行区分,因为它们都使用 script 元素。

modulePromise = import(specifier)

返回对由 specifier 标识的 模块脚本 的模块命名空间对象的 promise。这允许在运行时动态导入模块脚本,而不是使用静态的 import 语句形式。该指定符将相对于 活动脚本 进行 解析

如果给出了无效的指定符,或者在 获取 或评估生成的模块图时遇到错误,则返回的 promise 将被拒绝。

此语法可以在 传统模块脚本 中使用。因此,它为从传统脚本世界进入模块脚本世界提供了一个桥梁。

url = import.meta.url

返回 活动模块脚本基本 URL

此语法只能在 模块脚本 中使用。

url = import.meta.resolve(specifier)

返回相对于 活动脚本 进行 解析specifier。也就是说,这将返回通过使用 import(specifier) 导入的 URL。

如果给出了无效的指定符,则抛出 TypeError 异常。

此语法只能在 模块脚本 中使用。

模块映射是一个由映射构成的元组,它由URL 记录字符串组成。该URL 记录是模块被获取时的请求 URL,而字符串表示模块的类型(例如,“javascript-or-wasm”)。模块映射的值要么是模块脚本,要么是 null(用于表示获取失败),要么是占位符值“fetching”。模块映射用于确保导入的模块脚本在每个Documentworker中只被获取、解析和评估一次。

由于模块映射是按(URL,模块类型)进行索引的,因此以下代码将在模块映射中创建三个单独的条目,因为它会生成三个不同的(URL,模块类型)元组(所有元组的类型都是“javascript-or-wasm”)。

import "https://example.com/module.mjs";
import "https://example.com/module.mjs#map-buster";
import "https://example.com/module.mjs?debug=true";

也就是说,URL 的查询片段可以有所不同,从而在模块映射中创建不同的条目;它们不会被忽略。因此,将执行三次单独的获取和三次单独的模块评估。

相比之下,以下代码只会在模块映射中创建单个条目,因为在将URL 解析器应用于这些输入后,生成的URL 记录是相等的。

import "https://example.com/module2.mjs";
import "https:example.com/module2.mjs";
import "https://///example.com\\module2.mjs";
import "https://example.com/foo/../module2.mjs";

因此,在这个第二个示例中,只会发生一次获取和一次模块评估。

请注意,此行为与共享 worker按其解析后的构造函数 URL进行索引的方式相同。

由于模块类型也是模块映射键的一部分,因此以下代码将在模块映射中创建两个单独的条目(第一个的类型是“javascript-or-wasm”,第二个的类型是“css”)。

<script type=module>
  import "https://example.com/module";
</script>
<script type=module>
  import "https://example.com/module" with { type: "css" };
</script>

这会导致执行两次单独的获取和两次单独的模块评估。

在实践中,由于尚未指定的内存缓存(请参见问题#6110),资源可能只会在基于 WebKit 和 Blink 的浏览器中被获取一次。此外,只要所有模块类型都是相互排斥的,获取单个模块脚本中的模块类型检查至少会对其中一个导入失败,因此最多只执行一次模块评估。

模块映射键中包含类型的目的是,使用错误类型属性的导入不会阻止使用相同说明符但类型正确的其他导入成功。

当从另一个 JavaScript 模块导入时,JavaScript 模块脚本是默认的导入类型;也就是说,当import语句缺少type导入属性时,导入的模块脚本的类型将是 JavaScript。尝试使用具有type导入属性的import语句导入 JavaScript 资源将失败。

<script type="module">
    // All of the following will fail, assuming that the imported .mjs files are served with a
    // JavaScript MIME type. JavaScript module scripts are the default and cannot be imported with
    // any import type attribute.
    import foo from "./foo.mjs" with { type: "javascript" };
    import foo2 from "./foo2.mjs" with { type: "js" };
    import foo3 from "./foo3.mjs" with { type: "" };
    await import("./foo4.mjs", { with: { type: null } });
    await import("./foo5.mjs", { with: { type: undefined } });
</script>
8.1.6.7.1 HostGetImportMetaProperties(moduleRecord)

Reference/Operators/import.meta/resolve

在所有当前引擎中支持。

Firefox106+Safari16.4+Chrome105+
Opera?Edge105+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

Reference/Operators/import.meta

在所有当前引擎中支持。

Firefox62+Safari11.1+Chrome64+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS12+Chrome Android?WebView Android?Samsung Internet?Opera Android?

JavaScript 包含一个实现定义的HostGetImportMetaProperties 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]

  1. moduleScriptmoduleRecord.[[HostDefined]]。

  2. 断言moduleScript基本 URL不为 null,因为 moduleScript 是一个JavaScript 模块脚本

  3. urlStringmoduleScript基本 URL序列化

  4. steps 为以下步骤,给定参数 specifier

    1. specifier 设置为 ? ToString(specifier).

    2. url 为给定 moduleScriptspecifier解析模块说明符的结果。

    3. 返回 url序列化

  5. resolveFunction 为 ! CreateBuiltinFunction(steps, 1, "resolve", « »).

  6. 返回 « 记录 { [[Key]]: "url", [[Value]]: urlString }, 记录 { [[Key]]: "resolve", [[Value]]: resolveFunction } ».

8.1.6.7.2 HostGetSupportedImportAttributes()

《导入属性》提案包含一个实现定义的HostGetSupportedImportAttributes 抽象操作。用户代理必须使用以下实现:[JSIMPORTATTRIBUTES]

  1. 返回 « "type" »。

8.1.6.7.3 HostLoadImportedModule(referrer, moduleRequest, loadState, payload)

JavaScript 包含一个实现定义的HostLoadImportedModule 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]

  1. settingsObject当前设置对象

  2. 如果 settingsObject全局对象实现了WorkletGlobalScopeServiceWorkerGlobalScope,并且 loadState 未定义,则

    loadState 在当前获取过程由动态import()调用(直接或加载动态导入模块的传递依赖关系时)启动时为未定义。

    1. completion完成记录 { [[Type]]: throw, [[Value]]: 新的TypeError,[[Target]]: empty }。

    2. 执行FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).

    3. 返回。

  3. referencingScript 为 null。

  4. originalFetchOptions默认脚本获取选项

  5. fetchReferrer 为 "client"。

  6. 如果 referrer脚本记录循环模块记录,则

    1. referencingScript 设置为 referrer.[[HostDefined]]。

    2. settingsObject 设置为 referencingScript设置对象

    3. fetchReferrer 设置为 referencingScript基本 URL

    4. originalFetchOptions 设置为 referencingScript获取选项

    referrer 通常是脚本记录循环模块记录,但它不会是获取事件处理程序的当前值算法中的事件处理程序。例如,给定

    <button onclick="import('./foo.mjs')">Click me</button>

    如果click事件发生,则在import()表达式运行时,GetActiveScriptOrModule将返回 null,此操作将接收当前领域作为回退 referrer

  7. 如果 referrer循环模块记录,并且 moduleRequest 等于 referrer.[[RequestedModules]] 的第一个元素,则

    1. 对于模块请求记录 requestedreferrer.[[RequestedModules]]

      1. 如果 moduleRequest.[[Attributes]] 包含一个记录 entry,使得 entry.[[Key]] 不为 "type",则

        1. completion完成记录 { [[Type]]: throw, [[Value]]: 新的SyntaxError 异常,[[Target]]: empty }。

        2. 执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。

        3. 返回。

        JavaScript 规范重新执行此验证,但此处重复是为了避免在验证失败时不必要地加载任何依赖项。

      2. 根据 referencingScriptmoduleRequest.[[Specifier]] 解析模块说明符,捕获任何异常。如果它们抛出异常,则将 resolutionError 设置为抛出的异常。

      3. 如果上一步抛出异常,则

        1. completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }。

        2. 执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。

        3. 返回。

      4. moduleType 设置为根据 moduleRequest 运行 模块类型从模块请求 步骤的结果。

      5. 如果根据 moduleTypesettings 运行 允许的模块类型 步骤的结果为 false,则

        1. completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: 新的 TypeError 异常,[[Target]]: empty }。

        2. 执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。

        3. 返回。

      此步骤实质上是在对静态模块依赖项列表进行首次调用 HostLoadImportedModule 时验证所有请求的模块说明符和类型属性,以避免在任何一个依赖项具有静态错误的情况下进一步加载操作。我们将具有无法解析的模块说明符或不受支持的类型属性的模块视为无法解析的模块;在这两种情况下,语法问题都使得以后无法考虑链接该模块。

  8. 根据 settingsObject 禁止进一步导入映射

  9. url 设置为根据 referencingScriptmoduleRequest.[[Specifier]] 解析模块说明符 的结果,捕获任何异常。如果它们抛出异常,则将 resolutionError 设置为抛出的异常。

  10. 如果上一步抛出异常,则

    1. completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }。

    2. 执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。

    3. 返回。

  11. fetchOptions 设置为根据 originalFetchOptionsurlsettingsObject 获取后代脚本获取选项 的结果。

  12. destination 设置为 "script"

  13. fetchClient 设置为 settingsObject

  14. 如果 loadState 不为 undefined,则

    1. destination 设置为 loadState.[[Destination]]。

    2. fetchClient 设置为 loadState.[[FetchClient]]。

  15. 根据 urlfetchClientdestinationfetchOptionssettingsObjectfetchReferrermoduleRequestonSingleFetchComplete(如下定义)获取单个导入的模块脚本。如果 loadState 不为 undefined 且 loadState.[[PerformFetch]] 不为 null,则将 loadState.[[PerformFetch]] 作为参数传递。

    给定 moduleScriptonSingleFetchComplete 是以下算法

    1. completion 设置为 null。

    2. 如果 moduleScript 为 null,则将 completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: 新的 TypeError,[[Target]]: empty }。

    3. 否则,如果 moduleScript解析错误 不为 null,则

      1. parseError 设置为 moduleScript解析错误

      2. completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: parseError, [[Target]]: empty }。

      3. 如果 loadState 不为 undefined 且 loadState.[[ParseError]] 为 null,则将 loadState.[[ParseError]] 设置为 parseError

    4. 否则,将 completion 设置为 完成记录 { [[Type]]: normal, [[Value]]: moduleScript记录,[[Target]]: empty }。

    5. 执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。

8.1.7 事件循环

8.1.7.1 定义

为了协调事件、用户交互、脚本、渲染、网络等,用户代理必须使用本节所述的 事件循环。每个 代理 都有一个与之关联的 事件循环,该循环是该代理所独有的。

一个 同源窗口代理事件循环 被称为 窗口事件循环。一个 专用工作线程代理共享工作线程代理服务工作线程代理事件循环 被称为 工作线程事件循环。一个 工作线程代理事件循环 被称为 工作线程事件循环

事件循环 不一定对应于实现线程。例如,多个 窗口事件循环 可以在一个线程中协同调度。

但是,对于分配了 [[CanBlock]] 设置为 true 的各种工作线程 代理,JavaScript 规范确实对它们在 向前进展 方面的要求,这实际上相当于在这些情况下要求专用每个代理的线程。


一个 事件循环 有一个或多个 任务队列。一个 任务队列 是一个 集合,其中包含 任务

任务队列集合,而不是 队列,因为 事件循环处理模型 从选定的队列中获取第一个 可运行任务,而不是 出队 第一个任务。

微任务队列 不是 任务队列

任务封装了负责以下工作的算法

事件

在特定 EventTarget 对象上分派 Event 对象通常由一个专用的任务完成。

并非所有事件都使用 任务队列 分派;许多事件是在其他任务期间分派的。

解析

HTML 解析器 对一个或多个字节进行标记,然后处理任何生成的标记,这通常是一个任务。

回调

调用回调通常由一个专用的任务完成。

使用资源

当算法 获取 资源时,如果获取以非阻塞方式发生,则一旦资源的某些部分或全部可用,就会通过任务来处理资源。

对 DOM 操作的反应

某些元素有在 DOM 操作时触发的任务,例如,当该元素 插入到文档中 时。

形式上,一个 任务 是一个 结构,它具有

步骤
一系列指定任务要完成的工作的步骤。
一个
一个 任务源,用于对相关任务进行分组和序列化。
一个 文档
与任务关联的 Document,或对于不在 窗口事件循环 中的任务,则为 null。
一个 脚本评估环境设置对象集
一个 集合,其中包含 环境设置对象,用于在任务期间跟踪脚本评估。

如果任务的 文档 为 null 或 完全激活,则该 任务可运行

根据其 字段,每个 任务 都被定义为来自特定 任务源。对于每个 事件循环,每个 任务源 都必须与特定的 任务队列 相关联。

本质上,任务源 用于标准中将逻辑上不同的任务类型分开,而用户代理可能希望在这些任务类型之间进行区分。任务队列 用于用户代理在给定的 事件循环 中合并任务源。

例如,用户代理可以为鼠标和键盘事件创建一个 任务队列(与 用户交互任务源 相关联),另一个用于与所有其他 任务源 相关联。然后,利用 事件循环处理模型 的初始步骤中给予的自由度,它可以四分之三的时间内优先处理键盘和鼠标事件,保持界面响应,但不会使其他任务队列饿死。请注意,在此设置中,处理模型仍然强制要求用户代理绝不会以乱序方式处理来自任何一个 任务源 的事件。


每个 事件循环 都有一个 当前正在运行的任务,它是一个 任务 或 null。最初,它是 null。它用于处理重入。

每个 事件循环 都有一个 微任务队列,它是一个 队列,其中包含 微任务,最初为空。一个 微任务 是指通过 排队一个微任务 算法创建的 任务 的非正式说法。

每个 事件循环 都有一个 执行微任务检查点 布尔值,它最初为 false。它用于防止 执行微任务检查点 算法的重入调用。

每个 窗口事件循环 都有一个 DOMHighResTimeStamp 上次渲染机会时间,最初设置为零。

每个 窗口事件循环 都有一个 DOMHighResTimeStamp 上次空闲时段开始时间,最初设置为零。

要获取 窗口事件循环 loop同循环窗口,返回所有 Window 对象,这些对象的 相关代理事件循环loop

8.1.7.2 排队任务

要对 任务源 source 排队一个任务,它执行一系列步骤 steps,可选地给出事件循环 event loop 和文档 document

  1. 如果未给出 event loop,则将 event loop 设置为 隐式事件循环

  2. 如果未给出 document,则将 document 设置为 隐式文档

  3. task 为一个新的 任务

  4. task步骤 设置为 steps

  5. task 设置为 source

  6. task文档 设置为 document

  7. task脚本评估环境设置对象集 设置为空的

  8. queue任务队列sourceevent loop 上与它相关联。

  9. 追加 taskqueue

未能传递事件循环和文档到 排队一个任务 意味着依赖模棱两可且定义不明确的 隐式事件循环隐式文档 概念。规范作者应该始终传递这些值,或者使用包装算法 排队一个全局任务排队一个元素任务。建议使用包装算法。

要对 任务源 source 排队一个全局任务,具有一个 全局对象 global 和一系列步骤 steps

  1. event loopglobal相关代理事件循环

  2. documentglobal关联的 Document,如果 global 是一个 Window 对象;否则为 null。

  3. 排队一个任务,给出 sourceevent loopdocumentsteps

要对 任务源 source 排队一个元素任务,具有一个元素 element 和一系列步骤 steps

  1. globalelement相关全局对象

  2. 排队一个全局任务,给出 sourceglobalsteps

排队一个微任务,它执行一系列步骤 steps,可选地给出文档 document

  1. 断言:存在一个 周围代理。也就是说,此算法不会在 并行 时调用。

  2. eventLoop周围代理事件循环

  3. 如果未给出 document,则将 document 设置为 隐式文档

  4. microtask 为一个新的 任务

  5. microtask步骤 设置为 steps

  6. microtask 设置为 微任务任务源

  7. microtask文档 设置为 document

  8. microtask脚本评估环境设置对象集 设置为空的

  9. 入队 microtaskeventLoop微任务队列

微任务可能被移动到常规的 任务队列 中,如果,在它最初执行期间,它 旋转事件循环。这是唯一一个咨询微任务的 文档脚本评估环境设置对象集 的情况;它们被 执行微任务检查点 算法忽略。

在排队任务时,隐式事件循环 是可以从调用算法的上下文中推断出的循环。这通常是不言而喻的,因为大多数规范算法只涉及单个 代理(因此只有一个 事件循环)。例外情况是涉及或指定跨代理通信的算法(例如,在窗口和工作线程之间);对于这些情况,隐式事件循环 概念不能依赖,规范在 排队一个任务 时必须明确提供一个 事件循环

在事件循环 event loop 上排队任务时,隐式文档 的确定方式如下

  1. 如果 event loop 不是 窗口事件循环,则返回 null。

  2. 如果任务是在元素的上下文中排队的,则返回元素的 节点文档

  3. 如果任务是在 浏览上下文 的上下文中排队的,则返回浏览上下文的 活动文档

  4. 如果任务是由或为 脚本 排队的,则返回脚本的 设置对象全局对象关联的 Document

  5. 断言:永远不会到达此步骤,因为前面条件之一为真。 真的吗?

既有 隐式事件循环 也有 隐式文档 定义模糊,而且存在很多远程动作。希望能够消除这些,特别是 隐式文档。参见 问题 #4980

8.1.7.3 处理模型

一个 事件循环 必须不断运行以下步骤,只要它存在

  1. oldestTasktaskStartTime 为 null。

  2. 如果 事件循环 具有一个 任务队列,其中至少有一个 可运行任务,则

    1. taskQueue 为这样一个 任务队列,以 实现定义 的方式选择。

      请记住,微任务队列 不是 任务队列,因此不会在此步骤中选择它。但是,与 微任务任务源 相关联的 任务队列 可能在此步骤中被选中。在这种情况下,下一步中选定的 任务 最初是一个 微任务,但它作为 旋转事件循环 的一部分被移动了。

    2. taskStartTime 设置为 不安全的共享当前时间

    3. oldestTask 设置为 taskQueue 中第一个 可运行任务,并从 taskQueue删除 它。

    4. 如果 oldestTask文档 不为 null,则 记录任务开始时间,给出 taskStartTimeoldestTask文档

    5. 事件循环当前正在运行的任务 设置为 oldestTask

    6. 执行 oldestTask步骤

    7. 事件循环当前正在运行的任务 设置回 null。

    8. 执行微任务检查点。.

  3. taskEndTime不安全的共享当前时间[HRT]

  4. 如果 oldestTask 不为 null,则

    1. top-level browsing contexts 为一个空的 集合

    2. 对于 oldestTask脚本评估环境设置对象集 中的每个 环境设置对象 settings

      1. globalsettings全局对象

      2. 如果 global 不是一个 Window 对象,则 继续

      3. 如果 global浏览上下文 为 null,则 继续

      4. tlbcglobal浏览上下文顶级浏览上下文

      5. 如果 tlbc 不为 null,则 将它追加到 top-level browsing contexts

    3. 报告长时间任务,传入 taskStartTimetaskEndTimetop-level browsing contextsoldestTask

    4. 如果 oldestTask文档 不为 null,则 记录任务结束时间,传入 taskEndTimeoldestTask文档

  5. 如果这是一个 窗口事件循环,并且在这个 事件循环任务队列 中没有 可运行任务,则

    1. 将这个 事件循环上次空闲期开始时间 设置为 不安全的共享当前时间

    2. computeDeadline 为以下步骤

      1. deadline 为这个 事件循环上次空闲期开始时间 加上 50。

        未来的 50 毫秒上限是为了确保对新的用户输入的响应时间在人类感知阈值内。

      2. hasPendingRenders 为 false。

      3. 对于这个 事件循环相同循环窗口 中的每个 windowInSameLoop

        1. 如果 windowInSameLoop动画帧回调映射 不为 ,或者用户代理认为 windowInSameLoop 可能有待处理的渲染更新,则将 hasPendingRenders 设置为 true。

        2. timerCallbackEstimates获取 windowInSameLoop活动计时器映射 的值的结果。

        3. 对于 timerCallbackEstimates 中的每个 timeoutDeadline,如果 timeoutDeadline 小于 deadline,则将 deadline 设置为 timeoutDeadline

      4. 如果 hasPendingRenders 为 true,则

        1. nextRenderDeadline 为这个 事件循环上次渲染机会时间 加上 (1000 除以当前刷新率)。

          刷新率可能是特定于硬件或实现的。对于 60Hz 的刷新率,nextRenderDeadline 将在 上次渲染机会时间 之后大约 16.67 毫秒。

        2. 如果 nextRenderDeadline 小于 deadline,则返回 nextRenderDeadline

      5. 返回 deadline

    3. 对于这个 事件循环相同循环窗口 中的每个 win,执行 开始空闲期算法,为 win 传入以下步骤:返回调用 computeDeadline 的结果, 粗化,传入 win相关设置对象跨域隔离功能[REQUESTIDLECALLBACK]

  6. 如果这是一个 工作线程事件循环,则

    1. 如果这个 事件循环代理 的单个 全局对象 是一个 支持的 DedicatedWorkerGlobalScope,并且用户代理认为它将从在此时更新其渲染中获益,则

      1. now当前高分辨率时间,传入 DedicatedWorkerGlobalScope[HRT]

      2. 运行那个 DedicatedWorkerGlobalScope 的动画帧回调,传入 now 作为时间戳。

      3. 更新那个专用工作线程的渲染,以反映当前状态。

      类似于在 窗口事件循环更新渲染 的注释,用户代理可以确定专用工作线程中渲染的速率。

    2. 如果 事件循环任务队列 中没有 任务,并且 WorkerGlobalScope 对象的 关闭 标志为 true,则销毁 事件循环,中止这些步骤,恢复在 Web 工作线程 部分下方描述的 运行工作线程 步骤。

一个 窗口事件循环 eventLoop 还必须 并行 运行以下步骤,只要它存在

  1. 等待至少一个 可导航活动文档相关代理事件循环eventLoop 可能有一个 渲染机会

  2. eventLoop上次渲染机会时间 设置为 不安全的共享当前时间

  3. 对于每个具有 渲染机会navigable,在 渲染任务源排队一个全局任务,传入 navigable活动窗口更新渲染

    这可能会导致对 更新渲染 的冗余调用。但是,这些调用将没有可观察到的效果,因为根据不必要的渲染步骤,将不需要任何渲染。实现可以引入进一步的优化,例如仅在未排队时才排队此任务。但是,请注意,与该任务关联的文档可能在该任务被处理之前变为非活动状态。

    1. frameTimestampeventLoop上次渲染机会时间

    2. docs 为所有 完全活动Document 对象,其 相关代理事件循环eventLoop,以任意顺序排序,但必须满足以下条件

      在下面遍历 docs 的步骤中,每个 Document 必须按在列表中找到的顺序进行处理。

    3. 过滤不可渲染文档:从 docs 中删除任何 Document 对象 doc,如果以下任何一项为 true

      除了检查 并行 步骤中的渲染机会,我们还需要在此检查渲染机会,因为某些共享相同 事件循环 的文档可能不会在同一时间拥有 渲染机会

    4. 不必要的渲染:从 docs 中移除所有满足以下条件的 Document 对象 doc

    5. docs 中移除所有用户代理认为出于其他原因最好跳过更新渲染的 Document 对象。

      标记为过滤不可渲染文档的步骤阻止用户代理在无法向用户呈现新内容时更新渲染。

      标记为不必要的渲染的步骤阻止用户代理在没有新内容需要绘制时更新渲染。

      此步骤允许用户代理阻止以下步骤出于其他原因运行,例如,确保某些 任务 在彼此之后立即执行,仅插入 微任务检查点(并且不插入,例如,动画帧回调)。具体而言,用户代理可能希望将计时器回调合并在一起,并且不进行中间渲染更新。

    6. 对于 docs 的每个 doc显示 doc

    7. 对于 docs 的每个 doc,如果其 可导航节点顶级可遍历节点,则为 doc 刷新自动聚焦候选

    8. 对于 docs 的每个 doc运行调整大小步骤,用于 doc[CSSOMVIEW]

    9. 对于 docs 的每个 doc运行滚动步骤,用于 doc[CSSOMVIEW]

    10. 对于 docs 的每个 doc评估媒体查询并报告更改,用于 doc[CSSOMVIEW]

    11. 对于 docs 的每个 doc更新动画并发送事件,用于 doc,将 相对高分辨率时间(给定 frameTimestampdoc相关全局对象 作为时间戳)传递到 [WEBANIMATIONS]

    12. 对于 docs 的每个 doc运行全屏步骤,用于 doc[FULLSCREEN]

    13. 对于 docs 的每个 doc,如果用户代理检测到与 CanvasRenderingContext2DOffscreenCanvasRenderingContext2D (context) 关联的后备存储已丢失,则它必须为每个这样的 context 运行 上下文丢失步骤

      1. 如果 contextCanvasRenderingContext2D,则将 canvas 设置为 contextcanvas 属性的值;否则,将 canvas 设置为 context关联的 OffscreenCanvas 对象

      2. context上下文丢失 设置为 true。

      3. 将渲染上下文重置为其默认状态,给定 context

      4. shouldRestore 设置为 触发名为 contextlost 的事件,该事件在 canvas 上,且 cancelable 属性被初始化为 true 的结果。

      5. 如果 shouldRestore 为 false,则中止这些步骤。

      6. 尝试通过使用 context 的属性创建后备存储并将它们与 context 关联来恢复 context。如果失败,则中止这些步骤。

      7. context上下文丢失 设置为 false。

      8. 触发名为 contextrestored 的事件,该事件在 canvas 上。

    14. 对于 docs 的每个 doc运行动画帧回调,用于 doc,将 相对高分辨率时间(给定 frameTimestampdoc相关全局对象 作为时间戳)传递到。

    15. unsafeStyleAndLayoutStartTime 设置为 不安全共享当前时间

    16. 对于 docs 的每个 doc

      1. resizeObserverDepth 设置为 0。

      2. 当为 true 时

        1. 重新计算样式并更新 doc 的布局。

        2. hadInitialVisibleContentVisibilityDetermination 设置为 false。

        3. 对于每个 'auto' 用作 'content-visibility' 的值 的元素 element

          1. 如果 element视口距离 未确定,并且它与 用户相关,则将 checkForInitialDetermination 设置为 true。否则,将 checkForInitialDetermination 设置为 false。

          2. 确定 element视口距离

          3. 如果 checkForInitialDetermination 为 true,并且 element 现在与 用户相关,则将 hadInitialVisibleContentVisibilityDetermination 设置为 true。

        4. 如果 hadInitialVisibleContentVisibilityDetermination 为 true,则继续

          此步骤的目的是为了使初始视口距离确定(立即生效)反映在循环之前步骤中执行的样式和布局计算中。除初始距离确定之外的距离确定将在下一个 渲染机会 生效。 [CSSCONTAIN]

        5. 在深度 resizeObserverDepth收集活动调整大小观察,用于 doc

        6. 如果 doc 具有活动调整大小观察

          1. resizeObserverDepth 设置为 广播活动调整大小观察(给定 doc)的结果。

          2. 继续.
        7. 否则,中断
      3. 如果 doc 已跳过调整大小观察,则 传递调整大小循环错误,给定 doc

    17. 对于 docs 的每个 doc,如果 doc聚焦区域 不是 可聚焦区域,则为 doc视口 运行 聚焦步骤,并将 doc相关全局对象导航 API在进行中的导航期间聚焦已更改 设置为 false。

      例如,这可能发生是因为元素添加了 hidden 属性,导致其停止 渲染。它也可能发生在 input 元素上,当元素被 禁用 时。

      这将 通常触发 blur 事件,以及可能触发的 change 事件。

      除了这种异步修复之外,如果 文档的聚焦区域 被删除,则还存在一个 同步修复。后者将 *不会* 触发 blurchange 事件。

    18. 对于 docs 的每个 doc执行待处理的过渡操作,用于 doc[CSSVIEWTRANSITIONS]

    19. 对于 docs 的每个 doc运行更新交集观察步骤,用于 doc,将 相对高分辨率时间(给定 nowdoc相关全局对象 作为时间戳)传递到。 [INTERSECTIONOBSERVER]

    20. 对于 docs 的每个 doc记录渲染时间,用于 doc,给定 unsafeStyleAndLayoutStartTime

    21. 对于 docs 中的每个 doc标记绘制时间 针对 doc

    22. 对于 docs 中的每个 doc,更新 doc 及其 节点可导航 的渲染或用户界面,以反映当前状态。

    23. 对于 docs 中的每个 doc处理顶层移除,给定 doc

如果用户代理当前能够将 可导航 的内容呈现给用户,则 可导航 具有 渲染机会,考虑硬件刷新率限制和用户代理出于性能原因的节流,但即使内容在视窗之外也认为内容可呈现。

可导航渲染机会 根据硬件限制(如显示刷新率)和其他因素(如页面性能或其 活动文档可见性状态 是否为 "visible")确定。渲染机会通常以规律的间隔发生。

本规范不强制执行任何特定模型来选择渲染机会。例如,如果浏览器试图实现 60Hz 的刷新率,则渲染机会最多每秒 60 次(大约 16.7 毫秒)发生一次。如果浏览器发现 可导航 无法持续这种速率,则它可能会将该 可导航 的速率降低到每秒 30 次渲染机会,而不是偶尔丢帧。同样,如果 可导航 不可見,用户代理可能會決定將該頁面降低到每秒 4 次渲染機會,甚至更少。


当用户代理要 执行微任务检查点

  1. 如果 事件循环执行微任务检查点 为真,则返回。

  2. 事件循环执行微任务检查点 设置为真。

  3. 事件循环微任务队列为空

    1. oldestMicrotask 设置为从 事件循环微任务队列出队 的结果。

    2. 事件循环当前正在运行的任务 设置为 oldestMicrotask

    3. 运行 oldestMicrotask

      这可能涉及调用脚本回调,最终调用 运行脚本后的清理 步骤,这些步骤会再次调用此 执行微任务检查点 算法,这就是为什么我们使用 执行微任务检查点 标志来避免重新进入的原因。

    4. 事件循环当前正在运行的任务 恢复为 null。

  4. 对于每个 环境设置对象 settingsObject,其 负责事件循环 是此 事件循环通知有关拒绝的承诺 给定 settingsObject全局对象

  5. 清理 Indexed Database 事务.

  6. 执行 ClearKeptObjects()。

    WeakRef.prototype.deref() 返回一个对象时,该对象将保持活动状态,直到下次调用 ClearKeptObjects(),之后它将再次成为垃圾回收的対象。

  7. 事件循环执行微任务检查点 设置为假。

  8. 记录微任务检查点的计时信息.


并行 运行的算法要 等待稳定状态 时,用户代理必须 排队一个微任务 来运行以下步骤,然后必须停止执行(算法的执行在微任务运行时恢复,如以下步骤所述)

  1. 运行算法的 同步部分

  2. 如果合适,恢复算法的 并行 执行,如算法步骤中所述。

同步部分 中的步骤用 ⌛ 标记。


要求 旋转事件循环 直到满足条件 goal 的算法步骤等同于替换以下算法步骤

  1. task 设置为 事件循环当前正在运行的任务

    task 可以是 微任务

  2. task source 设置为 task

  3. old stack 设置为 JavaScript 执行上下文栈 的副本。

  4. 清空 JavaScript 执行上下文栈

  5. 执行微任务检查点。.

    如果 task微任务,由于 执行微任务检查点 为真,此步骤将成为无操作。

  6. 并行:

    1. 等待直到满足条件 goal

    2. 排队一个任务task source 上,以

      1. JavaScript 执行上下文栈 替换为 old stack

      2. 执行原始算法中此 旋转事件循环 实例之后的任何步骤。

        这将恢复 task

  7. 停止 task,允许调用它的任何算法恢复。

    这将导致 事件循环 的主要步骤集或 执行微任务检查点 算法继续执行。

与本规范和其他规范中的其他算法不同,这些算法的行为类似于编程语言函数调用,旋转事件循环 更像是宏,它通过扩展为一系列步骤和操作,在使用位置节省了打字和缩进。

步骤为以下的算法

  1. 执行某事。

  2. 旋转事件循环 直到发生很棒的事情。

  3. 执行其他事情。

是简写,在“宏扩展”之后,将变为

  1. 执行某事。

  2. old stack 设置为 JavaScript 执行上下文栈 的副本。

  3. 清空 JavaScript 执行上下文栈

  4. 执行微任务检查点。.

  5. 并行:

    1. 等待直到发生很棒的事情。

    2. 排队一个任务 到执行“执行某事”的任务源上,以

      1. JavaScript 执行上下文栈 替换为 old stack

      2. 执行其他事情。

这是一个更完整的替换示例,其中事件循环从并行工作中排队的任务内部旋转。使用 旋转事件循环 的版本

  1. 并行:

    1. 执行并行操作 1。

    2. 排队一个任务DOM 操作任务源 上,以

      1. 执行任务操作 1。

      2. 旋转事件循环 直到发生很棒的事情。

      3. 执行任务操作 2。

    3. 执行并行操作 2。

完全展开的版本

  1. 并行:

    1. 执行并行操作 1。

    2. old stack 设置为 null。

    3. 排队一个任务DOM 操作任务源 上,以

      1. 执行任务操作 1。

      2. old stack 设置为 JavaScript 执行上下文栈 的副本。

      3. 清空 JavaScript 执行上下文栈

      4. 执行微任务检查点。.

    4. 等待直到发生很棒的事情。

    5. 排队一个任务DOM 操作任务源 上,以

      1. JavaScript 执行上下文栈 替换为 old stack

      2. 执行任务操作 2。

    6. 执行并行操作 2。


由于历史原因,本规范中的一些算法要求用户代理在运行 任务暂停,直到满足条件 goal。这意味着运行以下步骤

  1. global 设置为 当前全局对象

  2. timeBeforePause 设置为给定 global当前高分辨率时间

  3. 如有必要,更新任何 Document可导航 的渲染或用户界面,以反映当前状态。

  4. 等待直到满足条件 goal。当用户代理具有暂停的 任务 时,相应的 事件循环 不得运行更多 任务,当前正在运行的 任务 中的任何脚本必须阻塞。但是,用户代理在暂停时应该对用户输入保持响应,尽管能力降低,因为 事件循环 不会执行任何操作。

  5. 记录暂停时间 给定从 timeBeforePause 到给定 global当前高分辨率时间持续时间

暂停 对用户体验非常不利,尤其是在多个文档共享单个 事件循环 的场景中。鼓励用户代理尝试 暂停 的替代方案,例如 循环事件循环 甚至只是简单地继续执行,而根本不进行任何暂停,只要在保持与现有内容兼容的情况下可以这样做。如果发现一种不太激进的替代方案能够与 Web 兼容,本规范将很乐意进行更改。

在此期间,实现者应注意,用户代理可能尝试使用的各种替代方案可能会改变 事件循环 行为的细微方面,包括 任务微任务 的计时。即使这样做会导致它们违反 暂停 操作隐含的精确语义,实现也应继续尝试。

8.1.7.4 通用任务源

以下 任务源 用于本规范和其他规范中许多基本无关的功能。

DOM 操作任务源

任务源 用于对 DOM 操作做出反应的功能,例如当元素 插入文档 时以非阻塞方式发生的事情。

用户交互任务源

任务源 用于对用户交互做出反应的功能,例如键盘或鼠标输入。

对用户输入的响应发送的事件(例如 click 事件)必须使用 任务 排队,任务源为 用户交互任务源[UIEVENTS]

网络任务源

任务源 用于对网络活动做出反应的功能。

导航和遍历任务源

任务源 用于排队涉及 导航历史记录遍历 的任务。

渲染任务源

任务源 仅用于 更新渲染

8.1.7.5 从其他规范处理事件循环

编写与 事件循环 正确交互的规范可能很棘手。这加剧了本规范如何使用与并发模型无关的术语,因此我们说诸如 "事件循环" 和 "并行" 之类的词语,而不是使用更熟悉的特定于模型的术语,例如 "主线程" 或 "在后台线程上"。

默认情况下,规范文本通常在 事件循环 上运行。这来自正式的 事件循环处理模型,因为您最终可以将大多数算法追溯到 任务 排队 到那里。

任何 JavaScript 方法的算法步骤将由调用该方法的作者代码调用。作者代码只能通过排队的任务运行,通常起源于 script 处理模型 中的某个地方。

从这个起点开始,首要准则是,规范需要执行的任何会阻塞 事件循环 的工作必须与它 并行 执行。这包括(但不限于)

下一个复杂之处是,在 并行 的算法部分中,您不得创建或操作与特定 领域全局环境设置对象 关联的对象。(用更熟悉的术语来说,您不得直接从后台线程访问主线程工件。)这样做会导致 JavaScript 代码可观察到的数据竞争,毕竟,您的算法步骤正在并行 于 JavaScript 代码运行。

但是,您可以操作来自 Infra 的规范级数据结构和值,因为它们与领域无关。它们从未直接暴露给 JavaScript,除非进行特定的转换(通常 通过 Web IDL)。 [INFRA] [WEBIDL]

因此,要影响可观察的 JavaScript 对象的世界,您必须 排队一个全局任务 来执行任何此类操作。这确保您的步骤与 事件循环 上发生的其它事情正确交织在一起。此外,您必须在 排队全局任务 时选择一个 任务源;这控制着您的步骤与其它步骤的相对顺序。如果您不确定要使用哪个 任务源,请选择最适合的 通用任务源 之一。最后,您必须指出排队的任务与哪个 全局对象 相关联;这确保如果该全局对象处于非活动状态,则任务不会运行。

排队全局任务 的基础原语是 排队任务 算法。通常,排队全局任务 更好,因为它会自动选择正确的 事件循环,并在适当的情况下,选择 文档。较旧的规范通常使用 排队任务 以及 隐式事件循环隐式文档 概念,但这不鼓励这样做。

将所有这些放在一起,我们可以提供一个模板,用于典型需要异步执行工作的算法

  1. 执行任何同步设置工作,同时仍在 事件循环 上。这可能包括将 领域 特定的 JavaScript 值转换为与领域无关的规范级值。

  2. 并行 执行一组可能很昂贵的步骤,完全在与领域无关的值上进行操作,并生成与领域无关的结果。

  3. 排队一个全局任务,在指定的 任务源 上,并给定适当的 全局对象,将与领域无关的结果转换回 事件循环 上 JavaScript 对象的可观察世界上的可观察影响。

以下是一个算法,它在解析为 URL 后,对传入的 列表 input 中的 标量值字符串 进行 "加密"。

  1. urls 为一个空的 列表

  2. input 的每个 string

    1. parsed 为根据 编码解析 URL 相对于 当前设置对象 给定的 string 生成的结果。

    2. 如果 parsed 失败,则返回 一个使用 "SyntaxError" DOMException 拒绝的承诺

    3. serialized 为将 URL 序列化器 应用于 parsed 生成的结果。

    4. serialized 追加到 urls

  3. realm当前领域

  4. p 为一个新的承诺。

  5. 并行 运行以下步骤

    1. encryptedURLs 为一个空的 列表

    2. urls 的每个 url

      1. 等待 100 毫秒,让人们以为我们在进行繁重的加密。

      2. encrypted 为从 url 派生的一个新的 字符串,其第 n代码单元 等于 url 的第 n代码单元 加 13。

      3. encrypted 追加到 encryptedURLs

    3. 排队一个全局任务,在 网络任务源 上,给定 realm全局对象,执行以下步骤

      1. array encryptedURLs 转换为 JavaScript 数组(在 realm 中)的结果。

      2. 使用 array 解析 p

  6. 返回 p

以下是关于此算法的几个需要注意的地方

(关于最后两点,还可以参考whatwg/webidl 问题 #135whatwg/webidl 问题 #371,我们仍在考虑上述 Promise 解析模式的细微差别。)

需要注意的另一件事是,如果该算法是从 Web IDL 指定的操作(接受 sequence<USVString>)中调用的,则会自动将作者作为输入提供的领域特定的 JavaScript 对象转换为领域无关的 sequence<USVString> Web IDL 类型,然后我们将它视为列表,其中包含标量值字符串。因此,根据规范的结构方式,主事件循环上可能还有其他隐式步骤,这些步骤参与了准备并行运行的整个过程。

8.1.8 事件

8.1.8.1 事件处理程序

事件/事件处理程序

许多对象可以指定事件处理程序。这些充当指定它们的 对象上的非捕获事件监听器[DOM]

一个事件处理程序是一个结构,包含两个

事件处理程序通过两种方式暴露。

第一种方式,对所有事件处理程序都适用,是作为事件处理程序 IDL 属性

第二种方式是作为事件处理程序内容属性HTML 元素上的事件处理程序以及一些Window 对象上的事件处理程序通过这种方式暴露。

对于这两种方式,事件处理程序都是通过名称暴露的,该名称是一个字符串,始终以“on”开头,后面跟着处理程序打算处理的事件的名称。


大多数情况下,暴露事件处理程序的对象与添加相应事件监听器的对象相同。但是,bodyframeset 元素会暴露几个事件处理程序,这些处理程序会作用于元素的Window 对象(如果存在)。在任何情况下,我们都将该对象称为事件处理程序作用于的目标

确定事件处理程序的目标,给定一个EventTarget 对象eventTarget,该对象暴露了事件处理程序,以及一个事件处理程序名称name,将执行以下步骤

  1. 如果eventTarget不是body 元素或frameset 元素,则返回eventTarget

  2. 如果name不是WindowEventHandlers 接口混合的属性成员的名称,并且Window 反射的 body 元素事件处理程序集包含name,则返回eventTarget

  3. 如果eventTarget节点文档不是活动文档,则返回 null。

    这可能会发生在该对象是body 元素,但没有对应的Window 对象时,例如。

    此检查不一定会阻止bodyframeset 元素(这些元素不是其节点文档body 元素)到达下一步。特别是,在活动文档中创建的body 元素(可能使用document.createElement())但未连接,其对应的Window 对象也将作为通过该元素暴露的几个事件处理程序目标

  4. 返回eventTarget节点文档相关全局对象


每个指定了一个或多个事件处理程序EventTarget 对象都与一个关联的事件处理程序映射相关联,该映射是一个映射,用于将表示名称的字符串映射到事件处理程序

当创建一个指定了一个或多个事件处理程序EventTarget 对象时,其事件处理程序映射必须初始化,使其包含每个事件处理程序条目,这些事件处理程序将该对象作为目标,并且这些事件处理程序中的设置为其初始值。

条目事件处理程序映射中创建的顺序可能是任意的。它不会通过对映射进行操作的任何算法进行观察。

不会在对象的事件处理程序映射中为那些仅仅在该对象上暴露但将其他对象作为其目标事件处理程序创建条目


一个事件处理程序 IDL 属性 是一个 IDL 属性,用于特定的事件处理程序。IDL 属性的名称与名称相同,该事件处理程序

当调用事件处理程序 IDL 属性的 getter 时,必须运行以下步骤,其中 name 为名称。

  1. eventTarget确定事件处理程序的目标的结果,该结果基于此对象和 name

  2. 如果 eventTarget 为 null,则返回 null。

  3. 返回获取事件处理程序的当前值的结果,该结果基于 eventTargetname

当调用事件处理程序 IDL 属性的 setter 时,必须运行以下步骤,其中 name 为名称。

  1. eventTarget确定事件处理程序的目标的结果,该结果基于此对象和 name

  2. 如果 eventTarget 为 null,则返回。

  3. 如果给定值为 null,则停用事件处理程序,该结果基于 eventTargetname

  4. 否则

    1. handlerMapeventTarget事件处理程序映射

    2. eventHandlerhandlerMap[name]。

    3. eventHandler设置为给定值。

    4. 激活事件处理程序,该结果基于 eventTargetname

某些事件处理程序 IDL 属性有额外的要求,特别是onmessage 属性,该属性属于 MessagePort 对象。


一个事件处理程序内容属性 是一个内容属性,用于特定的事件处理程序。内容属性的名称与名称相同,该事件处理程序

当指定事件处理程序内容属性时,它们必须包含有效的 JavaScript 代码,这些代码在解析后将匹配 FunctionBody 产生式,在自动分号插入后。

以下属性更改步骤用于在事件处理程序内容属性事件处理程序之间进行同步:[DOM]

  1. 如果 namespace 不为 null,或者 localName 不是element 上的事件处理程序内容属性的名称,则返回。

  2. eventTarget确定事件处理程序的目标的结果,该结果基于 elementlocalName

  3. 如果 eventTarget 为 null,则返回。

  4. 如果 value 为 null,则停用事件处理程序,该结果基于 eventTargetlocalName

  5. 否则

    1. 如果元素的内联行为是否应被内容安全策略阻止?算法在element、"script attribute" 和 value 上执行时返回 "Blocked",则返回。 [CSP]

    2. handlerMapeventTarget事件处理程序映射

    3. eventHandlerhandlerMap[localName]。

    4. location 为触发执行这些步骤的脚本位置。

    5. eventHandler设置为内部原始未编译处理程序 value/location

    6. 激活事件处理程序,该结果基于 eventTargetlocalName

根据 DOM 标准,即使 oldValuevalue 相同(将属性设置为其当前值),这些步骤也会运行,但如果 oldValuevalue 都为 null(删除当前不存在的属性),则不会运行这些步骤。 [DOM]


为了停用事件处理程序,请提供 EventTarget 对象 eventTarget 和一个字符串 name,该字符串是名称,用于事件处理程序,运行以下步骤。

  1. handlerMapeventTarget事件处理程序映射

  2. eventHandlerhandlerMap[name]。

  3. eventHandler设置为 null。

  4. listenereventHandler侦听器

  5. 如果 listener 不为 null,则使用 eventTargetlistener删除事件侦听器

  6. eventHandler侦听器设置为 null。

为了擦除所有事件侦听器和处理程序,请提供 EventTarget 对象 eventTarget,运行以下步骤。

  1. 如果 eventTarget 具有关联的事件处理程序映射,则对于 eventTarget 的关联事件处理程序映射中的每个 nameeventHandler停用事件处理程序,该结果基于 eventTargetname

  2. 使用 eventTarget删除所有事件侦听器

此算法用于定义 document.open()

为了激活事件处理程序,请提供 EventTarget 对象 eventTarget 和一个字符串 name,该字符串是名称,用于事件处理程序,运行以下步骤。

  1. handlerMapeventTarget事件处理程序映射

  2. eventHandlerhandlerMap[name]。

  3. 如果 eventHandler侦听器不为 null,则返回。

  4. callback 为创建 Web IDL EventListener 实例的结果,该实例代表对一个参数的函数的引用,该函数执行事件处理程序处理算法的步骤,该算法基于 eventTargetname 和其参数。

    EventListener回调上下文可以是任意的;它不会影响事件处理程序处理算法的步骤。 [DOM]

    回调明确不是事件处理程序本身。每个事件处理程序最终都会注册相同的回调,即下面定义的算法,该算法负责调用正确的代码,并处理代码的返回值。

  5. listener 为一个新的事件侦听器,其类型是与 eventHandler 对应的事件处理程序事件类型,其回调callback

    为了清楚起见,事件侦听器不同于 EventListener

  6. 使用 eventTargetlistener添加事件侦听器

  7. eventHandler侦听器设置为 listener

事件侦听器注册仅在事件处理程序被设置为非 null,并且事件处理程序尚未激活时才会发生。由于侦听器按注册顺序调用,假设没有发生停用,则特定事件类型的事件侦听器的顺序将始终为

  1. 事件处理程序第一次被设置为非 null 之前使用 addEventListener() 注册的事件侦听器

  2. 然后是当前设置的回调(如果有)

  3. 最后是事件处理程序第一次被设置为非 null 之后使用 addEventListener() 注册的事件侦听器。

此示例演示了事件侦听器调用的顺序。如果用户在此示例中单击了按钮,页面将显示四个警报,文本分别为 "ONE"、"TWO"、"THREE" 和 "FOUR"。

<button id="test">Start Demo</button>
<script>
 var button = document.getElementById('test');
 button.addEventListener('click', function () { alert('ONE') }, false);
 button.setAttribute('onclick', "alert('NOT CALLED')"); // event handler listener is registered here
 button.addEventListener('click', function () { alert('THREE') }, false);
 button.onclick = function () { alert('TWO'); };
 button.addEventListener('click', function () { alert('FOUR') }, false);
</script>

但是,在以下示例中,事件处理程序在首次激活(及其事件侦听器被删除)后被停用,然后在稍后时间重新激活。页面将显示五个警报,文本分别为 "ONE"、"TWO"、"THREE"、"FOUR" 和 "FIVE",按顺序显示。

<button id="test">Start Demo</button>
<script>
 var button = document.getElementById('test');
 button.addEventListener('click', function () { alert('ONE') }, false);
 button.setAttribute('onclick', "alert('NOT CALLED')"); // event handler is activated here
 button.addEventListener('click', function () { alert('TWO') }, false);
 button.onclick = null;                                 // but deactivated here
 button.addEventListener('click', function () { alert('THREE') }, false);
 button.onclick = function () { alert('FOUR'); };       // and re-activated here
 button.addEventListener('click', function () { alert('FIVE') }, false);
</script>

事件对象实现的接口不会影响事件处理程序是否被触发。

事件处理程序处理算法 用于 EventTarget 对象 eventTarget、一个表示名称的字符串 name,用于事件处理程序和一个 Event 对象 event,如下所示。

  1. callback获取事件处理程序的当前值的结果,该结果基于 eventTargetname

  2. 如果 callback 为 null,则返回。

  3. 如果 event 是一个 ErrorEvent 对象,eventtype 是 "error",并且 eventcurrentTarget 实现了 WindowOrWorkerGlobalScope 混合,则将 special error event handling 设置为 true。否则,将 special error event handling 设置为 false。

  4. 按照以下步骤处理 Event 对象 event

    如果 special error event handling 为 true

    return value 设置为使用「eventmessageeventfilenameeventlinenoeventcolnoeventerror」、"rethrow" 以及 callback this value 设置为 eventcurrentTarget 调用 callback 的结果。

    否则

    return value 设置为使用「event」、"rethrow" 以及 callback this value 设置为 eventcurrentTarget 调用 callback 的结果。

    如果回调函数抛出异常,则重新抛出异常,并结束这些步骤。该异常将传播到 DOM 事件分发逻辑,然后 报告 该异常。

  5. 按照以下步骤处理 return value

    如果 event 是一个 BeforeUnloadEvent 对象,并且 eventtype 是 "beforeunload"

    在这种情况下,事件处理程序 IDL 属性 的类型将为 OnBeforeUnloadEventHandler,因此 return value 将被强制转换为 null 或 DOMString

    如果 return value 不为 null,则

    1. 设置 eventcanceled flag

    2. 如果 eventreturnValue 属性的值为空字符串,则将 eventreturnValue 属性的值设置为 return value

    如果 special error event handling 为 true

    如果 return value 为 true,则设置 eventcanceled flag

    否则

    如果 return value 为 false,则设置 eventcanceled flag

    如果我们因为 eventtype 是 "beforeunload" 但 event 不是 一个 BeforeUnloadEvent 对象而到达了这个“否则”子句,则 return value 永远不会为 false,因为在这种情况下,return value 将被强制转换为 null 或 DOMString


EventHandler 回调函数类型表示用于事件处理程序的回调。它在 Web IDL 中表示如下:

[LegacyTreatNonObjectAsNull]
callback EventHandlerNonNull = any (Event event);
typedef EventHandlerNonNull? EventHandler;

在 JavaScript 中,任何 Function 对象都实现了此接口。

例如,以下文档片段

<body onload="alert(this)" onclick="alert(this)">

...当文档加载时会导致显示一个提示“[object Window]”,以及当用户在页面中点击任何内容时显示一个提示“[object HTMLBodyElement]”。

该函数的返回值会影响是否取消该事件:如上所述,如果返回值为 false,则会取消该事件。

由于历史原因,平台中有两个例外情况:

由于历史原因,onerror 处理程序具有不同的参数。

[LegacyTreatNonObjectAsNull]
callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long colno, optional any error);
typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
window.onerror = (message, source, lineno, colno, error) => {};

类似地,onbeforeunload 处理程序具有不同的返回值。

[LegacyTreatNonObjectAsNull]
callback OnBeforeUnloadEventHandlerNonNull = DOMString? (Event event);
typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnloadEventHandler;

一个 内部原始未编译处理程序 是一个包含以下信息的元组:

当用户代理需要 获取事件处理程序的当前值 时,给定一个 EventTarget 对象 eventTarget 和一个字符串 name,该字符串是 事件处理程序名称,它必须运行以下步骤:

  1. handlerMap 设置为 eventTarget事件处理程序映射

  2. eventHandlerhandlerMap[name]。

  3. 如果 eventHandler 是一个 内部原始未编译处理程序,则

    1. 如果 eventTarget 是一个元素,则将 element 设置为 eventTarget,并将 document 设置为 element节点文档。否则,eventTarget 是一个 Window 对象,将 element 设置为 null,并将 document 设置为 eventTarget关联的 Document

    2. 如果 脚本被禁用,则对于 document 返回 null。

    3. body 设置为 eventHandler 中的未编译脚本主体。

    4. location 设置为脚本主体来源的位置,如 eventHandler 中所示。

    5. 如果 element 不为 null 并且 element表单所有者,则将 form owner 设置为该 表单所有者。否则,将 form owner 设置为 null。

    6. settings object 设置为 document相关设置对象

    7. 如果 body 无法解析为 FunctionBody 或解析检测到 早期错误,则执行以下子步骤:

      1. eventHandler 设置为 null。

        这不会 停用 事件处理程序,它还会 删除 事件处理程序的 监听器(如果存在)。

      2. syntaxError 设置为一个新的 SyntaxError 异常,该异常与 settings object 相关联,并描述了解析期间发生的错误。它应该基于 location,即脚本主体来源的位置。

      3. 报告 settings object全局对象syntaxError 异常。

      4. 返回null。

    8. settings object域执行上下文 推入 JavaScript 执行上下文堆栈;它现在是 正在运行的 JavaScript 执行上下文

      这是必要的,以便后续调用 OrdinaryFunctionCreate 发生在正确的 中。

    9. function 设置为调用 OrdinaryFunctionCreate 的结果,其参数如下:

      functionPrototype
      %Function.prototype%
      sourceText
      如果 nameonerror 并且 eventTarget 是一个 Window 对象
      将 "function "、name、"(event, source, lineno, colno, error) {"、U+000A LF、body、U+000A LF 和 "}" 连接起来形成的字符串。
      否则
      将 "function "、name、"(event) {"、U+000A LF、body、U+000A LF 和 "}" 连接起来形成的字符串。
      ParameterList
      如果 nameonerror 并且 eventTarget 是一个 Window 对象
      该函数具有五个参数,分别命名为 eventsourcelinenocolnoerror
      否则
      该函数具有一个名为 event 的参数。
      body
      以上解析 body 的结果。
      thisMode
      non-lexical-this
      scope
      1. realm 设置为 settings object

      2. scope 设置为 realm.[[GlobalEnv]]。

      3. 如果 eventHandler 是一个元素的 事件处理程序,则将 scope 设置为 NewObjectEnvironment(document,true,scope)。

        (否则,eventHandler 是一个 Window 对象的 事件处理程序。)

      4. 如果 form owner 不为空,则将 scope 设置为 NewObjectEnvironment(form owner, true, scope)。

      5. 如果 element 不为空,则将 scope 设置为 NewObjectEnvironment(element, true, scope)。

      6. 返回 scope

    10. JavaScript 执行上下文栈 中移除 settings object领域执行上下文

    11. function.[[ScriptOrModule]] 设置为 null。

      这样做是因为默认行为(将创建的函数与栈上最近的 脚本 关联)会导致路径依赖的结果。例如,一个首先由用户交互调用的事件处理程序最终将具有 null [[ScriptOrModule]](因为此时当 活动脚本 为 null 时,将首先调用此算法),而一个首先由从脚本分派事件调用的事件处理程序将具有其 [[ScriptOrModule]] 设置为该脚本。

      相反,我们只将 [[ScriptOrModule]] 始终设置为 null。这无论如何都更直观;将第一个分派事件的脚本与事件处理程序代码相关联的想法是可疑的。

      实际上,这只会影响通过 import() 解析相对 URL,后者会查询相关脚本的 基本 URL。将 [[ScriptOrModule]] 设置为 null 意味着 HostLoadImportedModule 将回退到 当前设置对象API 基本 URL

    12. eventHandler 设置为创建 Web IDL EventHandler 回调函数对象的返回值,该函数对象的引用是 function,并且其 回调上下文settings object

  4. 返回 eventHandler

8.1.8.2 元素上的事件处理程序、Document 对象和 Window 对象

以下是所有 HTML 元素 必须支持的 事件处理程序(以及它们相应的 事件处理程序事件类型),既作为 事件处理程序内容属性 又作为 事件处理程序 IDL 属性;以及所有 DocumentWindow 对象必须支持的事件处理程序,作为 事件处理程序 IDL 属性

事件处理程序 事件处理程序事件类型
onabort

HTMLMediaElement/abort_event

在所有当前引擎中支持。

Firefox9+Safari3.1+Chrome3+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
abort
onauxclick

Element/auxclick_event

Firefox53+SafariNoChrome55+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android53+Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
auxclick
onbeforeinput beforeinput
onbeforematch beforematch
onbeforetoggle beforetoggle
oncancel

HTMLDialogElement/cancel_event

在所有当前引擎中支持。

Firefox98+Safari15.4+Chrome37+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome AndroidNoWebView Android?Samsung Internet?Opera Android?
cancel
oncanplay

HTMLMediaElement/canplay_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
canplay
oncanplaythrough

HTMLMediaElement/canplaythrough_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
canplaythrough
onchange

HTMLElement/change_event

在所有当前引擎中支持。

Firefox1+Safari3+Chrome1+
Opera9+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android10.1+
change
onclick

Element/click_event

在所有当前引擎中支持。

Firefox6+Safari3+Chrome1+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android6+Safari iOS1+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
click
onclose close
oncontextlost contextlost
oncontextmenu contextmenu
oncontextrestored contextrestored
oncopy

Element/copy_event

在所有当前引擎中支持。

Firefox22+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
copy
oncuechange

HTMLTrackElement/cuechange_event

在所有当前引擎中支持。

Firefox68+Safari10+Chrome32+
Opera19+Edge79+
Edge (Legacy)14+Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android4.4.3+Samsung Internet?Opera Android19+
cuechange
oncut

Element/cut_event

在所有当前引擎中支持。

Firefox22+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
cut
ondblclick

Element/dblclick_event

在所有当前引擎中支持。

Firefox6+Safari3+Chrome1+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer8+
Firefox Android6+Safari iOS1+Chrome AndroidNoWebView Android?Samsung Internet?Opera Android12.1+
dblclick
ondrag drag
ondragend dragend
ondragenter dragenter
ondragleave dragleave
ondragover dragover
ondragstart dragstart
ondrop drop
ondurationchange

HTMLMediaElement/durationchange_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
durationchange
onemptied

HTMLMediaElement/emptied_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
emptied
onended

HTMLMediaElement/ended_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
ended
onformdata formdata
oninput

HTMLElement/input_event

在所有当前引擎中支持。

Firefox6+Safari3.1+Chrome1+
Opera11.6+Edge79+
Edge (Legacy)NoInternet Explorer🔰 9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+
input
oninvalid invalid
onkeydown

Element/keydown_event

在所有当前引擎中支持。

Firefox6+Safari1.2+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
keydown
onkeypress keypress
onkeyup

Element/keyup_event

在所有当前引擎中支持。

Firefox6+Safari1.2+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
keyup
onloadeddata

HTMLMediaElement/loadeddata_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
loadeddata
onloadedmetadata

HTMLMediaElement/loadedmetadata_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
loadedmetadata
onloadstart

HTMLMediaElement/loadstart_event

在所有当前引擎中支持。

Firefox6+Safari4+Chrome3+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
loadstart
onmousedown

Element/mousedown_event

在所有当前引擎中支持。

Firefox6+Safari4+Chrome2+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android12.1+
mousedown
onmouseenter

Element/mouseenter_event

在所有当前引擎中支持。

Firefox10+Safari7+Chrome30+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer5.5+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android?
mouseenter
onmouseleave

Element/mouseleave_event

在所有当前引擎中支持。

Firefox10+Safari7+Chrome30+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer5.5+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android?
mouseleave
onmousemove

Element/mousemove_event

在所有当前引擎中支持。

Firefox6+Safari4+Chrome2+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android12.1+
mousemove
onmouseout

Element/mouseout_event

在所有当前引擎中支持。

Firefox6+Safari1+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android12.1+
mouseout
onmouseover

Element/mouseover_event

在所有当前引擎中支持。

Firefox6+Safari4+Chrome2+
Opera9.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android10.1+
mouseover
onmouseup

Element/mouseup_event

在所有当前引擎中支持。

Firefox6+Safari4+Chrome2+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android12.1+
mouseup
onpaste

Element/paste_event

在所有当前引擎中支持。

Firefox22+Safari3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+三星浏览器?Opera Android12.1+
paste
onpause

HTMLMediaElement/pause_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
pause
onplay

HTMLMediaElement/play_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
play
onplaying

HTMLMediaElement/playing_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
playing
onprogress

HTMLMediaElement/progress_event

在所有当前引擎中支持。

Firefox6+Safari3.1+Chrome3+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
progress
onratechange

HTMLMediaElement/ratechange_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
ratechange
onreset reset
onscrollend

Document/scrollend_event

Firefox109+Safari不支持Chrome114+
Opera?Edge114+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

Element/scrollend_event

Firefox109+Safari不支持Chrome114+
Opera?Edge114+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
scrollend
onsecuritypolicyviolation

Element/securitypolicyviolation_event

在所有当前引擎中支持。

Firefox63+Safari10+Chrome41+
Opera?Edge79+
Edge (旧版)15+Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
securitypolicyviolation
onseeked

HTMLMediaElement/seeked_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
seeked
onseeking

HTMLMediaElement/seeking_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
seeking
onselect

HTMLInputElement/select_event

在所有当前引擎中支持。

Firefox6+Safari1+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+

HTMLTextAreaElement/select_event

在所有当前引擎中支持。

Firefox6+Safari1+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
select
onslotchange

HTMLSlotElement/slotchange_event

在所有当前引擎中支持。

Firefox63+Safari10.1+Chrome53+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
slotchange
onstalled

HTMLMediaElement/stalled_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
stalled
onsubmit

HTMLFormElement/submit_event

在所有当前引擎中支持。

Firefox1+Safari3+Chrome1+
Opera8+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS1+Chrome Android?WebView Android?三星浏览器?Opera Android10.1+
submit
onsuspend

HTMLMediaElement/suspend_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
suspend
ontimeupdate

HTMLMediaElement/timeupdate_event

在所有当前引擎中支持。

Firefox3.5+Safari3.1+Chrome3+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+
timeupdate
ontoggle toggle
onvolumechange

HTMLMediaElement/volumechange_event

在所有当前引擎中支持。

Firefox6+Safari3.1+Chrome3+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+三星浏览器?Opera Android12.1+
volumechange
onwaiting

HTMLMediaElement/waiting_event

在所有当前引擎中支持。

Firefox6+Safari3.1+Chrome3+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+三星浏览器?Opera Android12.1+
waiting
onwebkitanimationend webkitAnimationEnd
onwebkitanimationiteration webkitAnimationIteration
onwebkitanimationstart webkitAnimationStart
onwebkittransitionend webkitTransitionEnd
onwheel

Element/wheel_event

在所有当前引擎中支持。

Firefox17+Safari7+Chrome31+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS不支持Chrome Android?WebView Android?三星浏览器?Opera Android?
wheel

以下是所有 事件处理程序(及其对应的 事件处理程序事件类型),必须由所有 HTML 元素(除了 bodyframeset 元素,因为这两个元素既有 事件处理程序内容属性,又有 事件处理程序 IDL 属性)支持;必须由所有 Document 对象支持,作为 事件处理程序 IDL 属性;并且必须由所有 Window 对象支持,作为 事件处理程序 IDL 属性,在 Window 对象本身,以及通过对应的 事件处理程序内容属性事件处理程序 IDL 属性,暴露在由该 Window 对象的 关联 Document 所拥有的所有 bodyframeset 元素上

事件处理程序 事件处理程序事件类型
onblur

Element/blur_event

在所有当前引擎中支持。

Firefox24+Safari3.1+Chrome1+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+

Window/blur_event

在所有当前引擎中支持。

Firefox6+Safari5.1+Chrome5+
Opera12.1+Edge79+
Edge (旧版)12+Internet Explorer11
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android12.1+
blur
onerror

Window/error_event

在所有当前引擎中支持。

Firefox6+Safari5.1+Chrome10+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android?
error
onfocus

Element/focus_event

在所有当前引擎中支持。

Firefox24+Safari3.1+Chrome1+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+

Window/focus_event

在所有当前引擎中支持。

Firefox6+Safari5.1+Chrome5+
Opera12.1+Edge79+
Edge (旧版)12+Internet Explorer11
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android12.1+
focus
onload load
onresize resize
onscroll

Document/scroll_event

在所有当前引擎中支持。

Firefox6+Safari2+Chrome1+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+

Element/scroll_event

在所有当前引擎中支持。

Firefox6+Safari1.3+Chrome1+
Opera12.1+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12.1+
scroll

我们将此表第一列中列出的 事件处理程序名称集合 称为 Window-reflecting body element event handler set


以下是必须由 Window 对象支持的 事件处理程序(及其对应的 事件处理程序事件类型),作为 事件处理程序 IDL 属性,在 Window 对象本身,以及通过对应的 事件处理程序内容属性事件处理程序 IDL 属性,暴露在由该 Window 对象的 关联 Document 所拥有的所有 bodyframeset 元素上

事件处理程序 事件处理程序事件类型
onafterprint

Window/afterprint_event

在所有当前引擎中支持。

Firefox6+Safari13+Chrome63+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
afterprint
onbeforeprint

Window/beforeprint_event

在所有当前引擎中支持。

Firefox6+Safari13+Chrome63+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
beforeprint
onbeforeunload

Window/beforeunload_event

在所有当前引擎中支持。

Firefox1+Safari3+Chrome1+
Opera12+Edge79+
Edge (旧版)12+Internet Explorer4+
Firefox Android?Safari iOS1+Chrome Android?WebView Android?三星浏览器?Opera Android12+
beforeunload
onhashchange

Window/hashchange_event

在所有当前引擎中支持。

Firefox3.6+Safari5+Chrome8+
Opera10.6+Edge79+
Edge (Legacy)12+Internet Explorer8+
Firefox Android?Safari iOS5+Chrome Android?WebView Android37+三星浏览器?Opera Android11+
hashchange
onlanguagechange

Window/languagechange_event

在所有当前引擎中支持。

Firefox32+Safari10.1+Chrome37+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android4+Safari iOS?Chrome Android?WebView Android?三星浏览器4.0+Opera Android?
languagechange
onmessage

Window/message_event

在所有当前引擎中支持。

Firefox9+Safari4+Chrome60+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer8+
Firefox Android?Safari iOS4+Chrome Android?WebView Android?Samsung Internet?Opera Android47+
消息
onmessageerror

HTMLMediaElement/error_event

在所有当前引擎中支持。

Firefox6+Safari3.1+Chrome3+
Opera11.6+Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12+

Window/messageerror_event

在所有当前引擎中支持。

Firefox57+Safari16.4+Chrome60+
Opera?Edge79+
Edge (Legacy)18Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android47+
messageerror
onoffline

Window/offline_event

在所有当前引擎中支持。

Firefox9+Safari4+Chrome3+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android?
离线
ononline

Window/online_event

在所有当前引擎中支持。

Firefox9+Safari4+Chrome3+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer9+
Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android?
在线
onpageswap pageswap
onpagehide pagehide
onpagereveal pagereveal
onpageshow pageshow
onpopstate

Window/popstate_event

在所有当前引擎中支持。

Firefox4+Safari5+Chrome5+
Opera11.5+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS?Chrome Android?WebView Android37+Samsung Internet?Opera Android11.5+
popstate
onrejectionhandled

Window/rejectionhandled_event

在所有当前引擎中支持。

Firefox69+Safari11+Chrome49+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android?
rejectionhandled
onstorage

Window/storage_event

在所有当前引擎中支持。

Firefox45+Safari4+Chrome1+
Opera?Edge79+
Edge (Legacy)15+Internet Explorer9+
Firefox Android?Safari iOS4+Chrome Android?WebView Android37+Samsung Internet?Opera Android?
storage
onunhandledrejection

Window/unhandledrejection_event

在所有当前引擎中支持。

Firefox69+Safari11+Chrome49+
Opera?Edge79+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android?
unhandledrejection
onunload

Window/unload_event

在所有当前引擎中支持。

Firefox1+Safari3+Chrome1+
Opera4+Edge79+
Edge (旧版)12+Internet Explorer4+
Firefox Android?Safari iOS1+Chrome Android?WebView Android?三星浏览器?Opera Android10.1+
unload

此列表中的 事件处理程序WindowEventHandlers 接口混合作为 事件处理程序 IDL 属性 实现。


以下是必须在 Document 对象上作为 事件处理程序 IDL 属性 支持的 事件处理程序(及其对应的 事件处理程序事件类型

事件处理程序 事件处理程序事件类型
onreadystatechange readystatechange
onvisibilitychange

Document/visibilitychange_event

在所有当前引擎中支持。

Firefox56+Safari14.1+Chrome62+
Opera49+Edge79+
Edge (Legacy)18Internet Explorer🔰 10+
Firefox Android?Safari iOS?Chrome Android?WebView Android62+Samsung Internet?Opera Android46+
visibilitychange
8.1.8.2.1 IDL 定义
interface mixin GlobalEventHandlers {
  attribute EventHandler onabort;
  attribute EventHandler onauxclick;
  attribute EventHandler onbeforeinput;
  attribute EventHandler onbeforematch;
  attribute EventHandler onbeforetoggle;
  attribute EventHandler onblur;
  attribute EventHandler oncancel;
  attribute EventHandler oncanplay;
  attribute EventHandler oncanplaythrough;
  attribute EventHandler onchange;
  attribute EventHandler onclick;
  attribute EventHandler onclose;
  attribute EventHandler oncontextlost;
  attribute EventHandler oncontextmenu;
  attribute EventHandler oncontextrestored;
  attribute EventHandler oncopy;
  attribute EventHandler oncuechange;
  attribute EventHandler oncut;
  attribute EventHandler ondblclick;
  attribute EventHandler ondrag;
  attribute EventHandler ondragend;
  attribute EventHandler ondragenter;
  attribute EventHandler ondragleave;
  attribute EventHandler ondragover;
  attribute EventHandler ondragstart;
  attribute EventHandler ondrop;
  attribute EventHandler ondurationchange;
  attribute EventHandler onemptied;
  attribute EventHandler onended;
  attribute OnErrorEventHandler onerror;
  attribute EventHandler onfocus;
  attribute EventHandler onformdata;
  attribute EventHandler oninput;
  attribute EventHandler oninvalid;
  attribute EventHandler onkeydown;
  attribute EventHandler onkeypress;
  attribute EventHandler onkeyup;
  attribute EventHandler onload;
  attribute EventHandler onloadeddata;
  attribute EventHandler onloadedmetadata;
  attribute EventHandler onloadstart;
  attribute EventHandler onmousedown;
  [LegacyLenientThis] attribute EventHandler onmouseenter;
  [LegacyLenientThis] attribute EventHandler onmouseleave;
  attribute EventHandler onmousemove;
  attribute EventHandler onmouseout;
  attribute EventHandler onmouseover;
  attribute EventHandler onmouseup;
  attribute EventHandler onpaste;
  attribute EventHandler onpause;
  attribute EventHandler onplay;
  attribute EventHandler onplaying;
  attribute EventHandler onprogress;
  attribute EventHandler onratechange;
  attribute EventHandler onreset;
  attribute EventHandler onresize;
  attribute EventHandler onscroll;
  attribute EventHandler onscrollend;
  attribute EventHandler onsecuritypolicyviolation;
  attribute EventHandler onseeked;
  attribute EventHandler onseeking;
  attribute EventHandler onselect;
  attribute EventHandler onslotchange;
  attribute EventHandler onstalled;
  attribute EventHandler onsubmit;
  attribute EventHandler onsuspend;
  attribute EventHandler ontimeupdate;
  attribute EventHandler ontoggle;
  attribute EventHandler onvolumechange;
  attribute EventHandler onwaiting;
  attribute EventHandler onwebkitanimationend;
  attribute EventHandler onwebkitanimationiteration;
  attribute EventHandler onwebkitanimationstart;
  attribute EventHandler onwebkittransitionend;
  attribute EventHandler onwheel;
};

interface mixin WindowEventHandlers {
  attribute EventHandler onafterprint;
  attribute EventHandler onbeforeprint;
  attribute OnBeforeUnloadEventHandler onbeforeunload;
  attribute EventHandler onhashchange;
  attribute EventHandler onlanguagechange;
  attribute EventHandler onmessage;
  attribute EventHandler onmessageerror;
  attribute EventHandler onoffline;
  attribute EventHandler ononline;
  attribute EventHandler onpagehide;
  attribute EventHandler onpagereveal;
  attribute EventHandler onpageshow;
  attribute EventHandler onpageswap;
  attribute EventHandler onpopstate;
  attribute EventHandler onrejectionhandled;
  attribute EventHandler onstorage;
  attribute EventHandler onunhandledrejection;
  attribute EventHandler onunload;
};
8.1.8.3 事件触发

某些操作和方法被定义为在元素上触发事件。例如,click() 方法在 HTMLElement 接口上被定义为在元素上触发一个 click 事件。 [UIEVENTS]

target 上触发一个名为 e 的合成指针事件,并带有可选的 不可信标志,意味着运行以下步骤

  1. event 为使用 PointerEvent 创建事件 的结果。

  2. eventtype 属性初始化为 e

  3. eventbubblescancelable 属性初始化为 true。

  4. 设置 eventcomposed 标志

  5. 如果设置了 不可信标志,则将 eventisTrusted 属性初始化为 false。

  6. 根据当前密钥输入设备的状态(如果有)初始化 eventctrlKeyshiftKeyaltKeymetaKey 属性(对于任何不可用的密钥则为 false)。

  7. eventview 属性初始化为 target节点文档Window 对象(如果有),否则为 null。

  8. eventgetModifierState() 方法应返回适当的值来描述当前密钥输入设备的状态。

  9. 返回在 target分派 event 的结果。

触发 click 事件target 上意味着 target 上触发一个名为 click 的合成指针事件

8.2 WindowOrWorkerGlobalScope 混合

WindowOrWorkerGlobalScope 混合用于在 WindowWorkerGlobalScope 对象上公开 API。

鼓励其他标准使用 partial interface mixin WindowOrWorkerGlobalScope { … }; 以及适当的引用来进一步扩展它。

typedef (DOMString or Function or TrustedScript) TimerHandler;

interface mixin WindowOrWorkerGlobalScope {
  [Replaceable] readonly attribute USVString origin;
  readonly attribute boolean isSecureContext;
  readonly attribute boolean crossOriginIsolated;

  undefined reportError(any e);

  // base64 utility methods
  DOMString btoa(DOMString data);
  ByteString atob(DOMString data);

  // timers
  long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments);
  undefined clearTimeout(optional long id = 0);
  long setInterval(TimerHandler handler, optional long timeout = 0, any... arguments);
  undefined clearInterval(optional long id = 0);

  // microtask queuing
  undefined queueMicrotask(VoidFunction callback);

  // ImageBitmap
  Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, optional ImageBitmapOptions options = {});
  Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options = {});

  // structured cloning
  any structuredClone(any value, optional StructuredSerializeOptions options = {});
};
Window includes WindowOrWorkerGlobalScope;
WorkerGlobalScope includes WindowOrWorkerGlobalScope;
self.isSecureContext

isSecureContext

在所有当前引擎中支持。

Firefox49+Safari11.1+Chrome47+
Opera?Edge79+
Edge (旧版)15+Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回此全局对象是否表示一个 安全上下文[SECURE-CONTEXTS]

self.origin

origin

在所有当前引擎中支持。

Firefox54+Safari11+Chrome59+
Opera?Edge79+
Edge (Legacy)18Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回全局对象的 来源,序列化为字符串。

self.crossOriginIsolated

crossOriginIsolated

在所有当前引擎中支持。

Firefox72+Safari15.2+Chrome87+
Opera?Edge87+
Edge (Legacy)?Internet ExplorerNo
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回在此全局中运行的脚本是否允许使用需要跨源隔离的 API。这取决于 `Cross-Origin-Opener-Policy` 和 `Cross-Origin-Embedder-Policy` HTTP 响应头以及 "cross-origin-isolated" 特性。

强烈建议开发人员使用 self.origin 而不是 location.origin。前者返回环境的 来源,后者返回环境 URL 的来源。想象一下在 https://stargate.example/ 上的文档中执行以下脚本

var frame = document.createElement("iframe")
frame.onload = function() {
  var frameWin = frame.contentWindow
  console.log(frameWin.location.origin) // "null"
  console.log(frameWin.origin) // "https://stargate.example"
}
document.body.appendChild(frame)

self.origin 是一个更可靠的安全指标。

isSecureContext 获取器步骤是,如果 this相关设置对象 是一个 安全上下文,则返回 true,否则返回 false。

origin 获取器步骤是返回 this相关设置对象来源序列化

crossOriginIsolated 获取器步骤是返回 this相关设置对象跨源隔离能力

8.3 Base64 工具方法

atob()btoa() 方法允许开发人员将内容转换为 Base64 编码,反之亦然。

在这些 API 中,出于助记符目的,"b" 可以被视为代表 "binary"(二进制),而 "a" 代表 "ASCII"。然而实际上,主要出于历史原因,这些函数的输入和输出都是 Unicode 字符串。

result = self.btoa(data)

btoa

在所有当前引擎中支持。

Firefox1+Safari3+Chrome4+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS1+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+

接收输入数据,该数据为 Unicode 字符串,仅包含 U+0000 到 U+00FF 范围内的字符,每个字符分别代表一个值为 0x00 到 0xFF 的二进制字节,并将其转换为 base64 表示形式,然后返回结果。

如果输入字符串包含任何超出范围的字符,则抛出 "InvalidCharacterError" DOMException 异常。

result = self.atob(data)

atob

在所有当前引擎中支持。

Firefox1+Safari3+Chrome4+
Opera10.5+Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS1+Chrome Android?WebView Android37+Samsung Internet?Opera Android11+

接收输入数据,该数据为 Unicode 字符串,包含 base64 编码的二进制数据,对其进行解码,并返回一个由 U+0000 到 U+00FF 范围内的字符组成的字符串,每个字符分别代表一个值为 0x00 到 0xFF 的二进制字节,对应于该二进制数据。

如果输入字符串不是有效的 base64 数据,则抛出 "InvalidCharacterError" DOMException

btoa(data) 方法必须抛出 "InvalidCharacterError" DOMException,如果 data 包含任何代码点大于 U+00FF 的字符。否则,用户代理必须将 data 转换为一个字节序列,其第 n 个字节是 data 的第 n 个代码点的八位表示,然后必须对该字节序列应用 宽容的 base64 编码 并返回结果。

atob(data) 方法的步骤如下

  1. decodedData 为对 data 运行 宽容的 base64 解码 的结果。

  2. 如果 decodedData 为失败,则抛出 "InvalidCharacterError" DOMException

  3. 返回 decodedData