动态标准 — 最后更新于 2024 年 9 月 12 日
WindowOrWorkerGlobalScope
混合各种机制会导致作者提供的可执行代码在文档的上下文中运行。这些机制包括但不限于:
script
元素。javascript:
URL。addEventListener()
在 DOM 中注册的,还是通过显式 事件处理程序内容属性、事件处理程序 IDL 属性,还是以其他方式注册的。JavaScript 定义了代理的概念。本节介绍该语言级概念在 Web 平台上的映射。
从概念上讲,代理概念是一个与架构无关的理想化“线程”,JavaScript 代码在其中运行。此类代码可能涉及多个全局/ 领域,这些全局/ 领域 可以同步访问彼此,因此需要在单个执行线程中运行。
两个具有相同代理的 Window
对象并不意味着它们可以直接访问彼此领域中创建的所有对象。它们必须具有相同的来源域;请参阅 IsPlatformObjectSameOrigin。
Web 平台上存在以下类型的代理:
包含各种可能相互访问的 Window
对象,这些访问可能是直接的,也可能是通过使用 document.domain
实现的。
如果包含的代理集群的 is origin-keyed 属性为 true,则所有 Window
对象都将具有相同的来源,可以直接相互访问,并且 document.domain
将不执行任何操作。
两个具有相同来源的 Window
对象可以位于不同的同源窗口代理中,例如,如果它们各自位于自己的浏览上下文组中。
包含单个 DedicatedWorkerGlobalScope
对象。
包含单个 SharedWorkerGlobalScope
对象。
包含单个 ServiceWorkerGlobalScope
对象。
包含单个 WorkletGlobalScope
对象。
虽然给定的 worklet 可以具有多个领域,但每个这样的领域都需要自己的代理,因为每个领域可以独立于其他领域执行代码,并且可以与其他领域同时执行代码。
只有共享和专用工作线程代理允许使用 JavaScript Atomics API 来潜在地阻止。
为了创建代理,给定一个布尔值 canBlock:
令 signifier 为一个新的唯一内部值。
令 candidateExecution 为一个新的候选执行。
令 agent 为一个新的代理,其 [[CanBlock]] 为 canBlock,[[Signifier]] 为 signifier,[[CandidateExecution]] 为 candidateExecution,以及 [[IsLockFree1]]、[[IsLockFree2]] 和 [[LittleEndian]] 在实现的酌情决定下设置。
将 agent 的事件循环设置为一个新的事件循环。
返回 agent。
对于领域 realm,其 [[Signifier]] 为 realm.[[AgentSignifier]] 的代理是领域的代理。
平台对象 platformObject 的相关代理是 platformObject 的相关领域的代理。
当前领域的代理等效于周围代理。
JavaScript 还定义了代理集群的概念,本标准通过在使用获取同源窗口代理或获取工作线程/worklet 代理算法创建代理时适当地放置代理来将其映射到 Web 平台。
代理集群概念对于定义 JavaScript 内存模型至关重要,特别是对于哪些代理可以共享 SharedArrayBuffer
对象的底层数据。
从概念上讲,代理集群概念是一个与架构无关的理想化“进程边界”,它将多个“线程”(代理)分组在一起。规范中定义的代理集群通常比用户代理中实现的实际进程边界更严格。通过在规范级别强制执行这些理想化的划分,我们确保 Web 开发人员看到与共享内存相关的互操作行为,即使面对用户代理进程模型的变化和改变。
一个 代理集群 有一个关联的 跨域隔离模式,它是一个 跨域隔离模式。它最初是 "none
"。
一个 代理集群 有一个关联的 是否基于来源(一个布尔值),它最初是 false。
一个 代理集群键 是一个 站点 或 元组来源。如果没有 Web 开发人员采取措施来实现 基于来源的代理集群,它将是一个 站点。
另一种说法是,一个 代理集群键 可以是一个 方案和主机 或一个 来源。
要 获取同源窗口代理,给定一个 来源 origin,一个 浏览上下文组 group,以及一个布尔值 requestsOAC,执行以下步骤:
设 site 为使用 origin 获取站点 的结果。
设 key 为 site。
否则,如果 group 的 历史代理集群键映射[origin] 存在,则将 key 设置为 group 的 历史代理集群键映射[origin]。
否则
如果 requestsOAC 为 true,则将 key 设置为 origin。
将 group 的 历史代理集群键映射[origin] 设置为 key。
这意味着每个浏览上下文代理集群只有一个 同源窗口代理。(但是,专用工作者 和 工作者代理 可能在同一个集群中。)
以下定义了所有其他类型代理的 代理集群 的分配。
要 获取工作者/工作者代理,给定一个 环境设置对象 或 null outside settings,一个布尔值 isTopLevel,以及一个布尔值 canBlock,执行以下步骤:
设 agentCluster 为 null。
如果 isTopLevel 为 true,则
将 agentCluster 设置为一个新的 代理集群。
将 agentCluster 的 是否基于来源 设置为 true。
这些工作者可以被认为是基于来源的。但是,这不会通过任何 API 公开(与 originAgentCluster
对窗口公开基于来源的方式不同)。
否则
设 agent 为给定 canBlock 创建代理 的结果。
将 agent 添加到 agentCluster 中。
返回 agent。
要 获取专用/共享工作者代理,给定一个 环境设置对象 outside settings 以及一个布尔值 isShared,返回给定 outside settings、isShared 以及 true 获取工作者/工作者代理 的结果。
要 获取工作者代理,给定一个 环境设置对象 outside settings,返回给定 outside settings、false 以及 false 获取工作者/工作者代理 的结果。
要 获取服务工作者代理,返回给定 null、true 以及 false 获取工作者/工作者代理 的结果。
JavaScript 规范引入了 领域 概念,表示运行脚本的全局环境。每个领域都带有一个 实现定义的 全局对象;本规范的大部分内容都致力于定义该全局对象及其属性。
对于 Web 规范,将值或算法与领域/全局对象对关联起来通常很有用。当值特定于特定类型的领域时,它们直接与相关的全局对象关联,例如,在 Window
或 WorkerGlobalScope
接口的定义中。当值在多个领域中都有效时,我们使用 环境设置对象 概念。
最后,在某些情况下,需要在领域/全局对象/环境设置对象甚至不存在之前跟踪关联的值(例如,在 导航 期间)。这些值在 环境 概念中跟踪。
一个 环境 是一个对象,它标识当前或潜在的执行环境的设置(即,导航参数 的 保留环境 或 请求 的 保留客户端)。一个 环境 具有以下字段
一个不透明的字符串,它唯一标识此 环境。
在 Window
环境设置对象 的情况下,此 URL 可能与其 全局对象 的 关联的 Document
的 URL 不同,这是由于 history.pushState()
等机制修改了后者。
一个 目前 实现定义 值、null 或一个 来源。对于“顶层”潜在执行环境,它为 null(即,当还没有响应时);否则,它是“顶层” 环境 的 来源。对于专用工作者或工作程序,它是其创建者的 顶层来源。对于共享工作者或服务工作者,它是 实现定义 值。
一个标志,指示环境设置是否完成。它最初未设置。
规范可能会为环境定义 环境丢弃步骤。这些步骤以 环境 作为输入。
仅针对少数环境运行 环境丢弃步骤:那些永远不会变得执行就绪的环境,因为例如,它们无法加载。
一个 环境设置对象 是一个 环境,它另外指定了以下算法
一个 JavaScript 执行上下文,由使用该设置对象的所有 脚本 共享,即给定 领域 中的所有脚本。当我们 运行经典脚本 或 运行模块脚本 时,此执行上下文成为 JavaScript 执行上下文堆栈 的顶部,在该堆栈之上会推送另一个特定于该脚本的执行上下文。(此设置确保 源文本模块记录 的 Evaluate 知道要使用哪个领域。)
一个 模块映射,用于导入 JavaScript 模块。
一个 来源,用于安全检查。
一个 策略容器,包含用于安全检查的策略。
一个布尔值,表示使用此 环境设置对象 的脚本是否允许使用需要跨源隔离的 API。
一个 环境设置对象 的 负责事件循环 是其 全局对象 的 相关代理 的 事件循环。
一个 全局对象 是一个 JavaScript 对象,它是 领域 的 [[GlobalObject]] 字段。
在本规范中,所有 领域 都是使用 全局对象 创建 的,这些全局对象要么是 Window
、WorkerGlobalScope
或 WorkletGlobalScope
对象。
一个 全局对象 具有一个 处于错误报告模式 布尔值,它最初为 false。
一个 全局对象 具有一个 未决拒绝的承诺弱集,一个 集合,其中包含 Promise
对象,最初为空。此集合不得创建对其任何成员的强引用,并且实现可以在 实现定义 的方式下限制其大小,例如,当添加新条目时,从其中删除旧条目。
一个 全局对象 具有一个 即将被通知的拒绝的承诺列表,一个 列表,其中包含 Promise
对象,最初为空。
在 领域、全局对象 和 环境设置对象 之间始终存在一对一对应关系。
要 创建一个新的领域 在一个 代理 agent 中,可以选择性地包含创建全局对象或全局 this 绑定的指令,执行以下步骤
执行 InitializeHostDefinedRealm(),并提供创建全局对象和全局 this 绑定的定制化参数。
令 realm execution context 为 正在运行的 JavaScript 执行上下文。
这是在上一步骤中创建的 JavaScript 执行上下文。
从 JavaScript 执行上下文栈 中移除 realm execution context。
令 realm 为 realm execution context 的领域组件。
如果 agent 的 代理集群 的 跨域隔离模式 为 "none
",那么
这样做是为了与 web 内容兼容,我们希望在未来能移除它。Web 开发者仍然可以通过 new WebAssembly.Memory({ shared:true, initial:0, maximum:0 }).buffer.constructor
获取构造函数。
返回 realm execution context。
在整个规范中定义算法步骤时,通常需要说明要使用哪个 领域 — 或者等效地,要使用哪个 全局对象 或 环境设置对象。通常,至少有四种可能性
注意 入口、现任 和 当前 概念在没有限定词的情况下就可以使用,而 相关 概念必须应用于特定的 平台对象。
新的规范不应使用 现任 和 入口 概念,因为它们过于复杂,使用起来不直观。我们正在努力从平台中移除几乎所有现有的使用方式:有关 现任 的信息,请参见 issue #1430,有关 入口 的信息,请参见 issue #1431。
通常,web 平台规范应该使用 相关 概念,应用于正在操作的对象(通常是当前方法的 this 值)。这与 JavaScript 规范不符,在 JavaScript 规范中,当前 通常用作默认值(例如,在确定 领域 的 Array
构造函数应用于在 Array.prototype.map
中构建结果时)。但是这种不一致已经深深地嵌入到平台中,以至于我们必须接受这种状态。
考虑以下页面,a.html
加载在浏览器窗口中,b.html
加载在 iframe
中(如所示),c.html
和 d.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。由于这是不可取的,因此该算法改为使用 相关领域,从而得到上面注释中所示的合理结果。
本节的其余部分将正式定义 入口、现任、当前 和 相关 概念。
调用脚本 的过程将在 JavaScript 执行上下文栈 上推送或弹出 领域执行上下文,并穿插其他 执行上下文。
有了这些内容,我们将 入口执行上下文 定义为 JavaScript 执行上下文栈 中最最近推送的 领域执行上下文。 入口领域 是 入口执行上下文 的领域组件。
所有 JavaScript 执行上下文 必须在其代码评估状态中包含一个 跳过确定现任计数器 值,该值最初为零。在 准备运行回调 和 清理运行回调后的结果 的过程中,此值将递增和递减。
每个 事件循环 都有一个关联的 备份当前设置对象栈,最初为空。简单来说,它用于在没有作者代码在栈上时确定 当前设置对象,但作者代码负责以某种方式运行当前算法。 准备运行回调 和 运行回调后的清理 操作会操作这个栈。 [WEBIDL]
当使用 Web IDL 调用 作者代码,或者当 HostEnqueuePromiseJob 调用 Promise 任务时,它们使用以下算法来跟踪相关数据以确定 当前设置对象
要 准备运行一个回调,使用 环境设置对象 settings
将 settings 推入 备份当前设置对象栈。
令 context 为 最顶层的具有执行上下文的脚本。
如果 context 不为空,则增加 context 的 在确定当前时跳过的计数器。
要 运行回调后的清理,使用 环境设置对象 settings
令 context 为 最顶层的具有执行上下文的脚本。
这将与 准备运行回调 相应调用中的 最顶层的具有执行上下文的脚本 相同。
如果 context 不为空,则减少 context 的 在确定当前时跳过的计数器。
从 备份当前设置对象栈 中移除 settings。
这里,最顶层的具有执行上下文的脚本 是 JavaScript 执行上下文栈 中具有非空 ScriptOrModule 组件的最顶层条目,或者如果 JavaScript 执行上下文栈 中没有这样的条目,则为 null。
有了所有这些,当前设置对象 将按如下方式确定
令 context 为 最顶层的具有执行上下文的脚本。
如果 context 为 null,或者如果 context 的 在确定当前时跳过的计数器 大于零,则
返回 context 的 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,并且没有东西会增加其 在确定当前时跳过的计数器。
调用回调然后调用 bound
,bound
反过来调用 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平台上唯一合理的现任概念使用场景;在所有其他情况下,使用它的后果只是令人困惑,我们希望有一天将它们切换为使用当前或相关,具体取决于情况。
JavaScript规范定义了当前领域,也称为“当前领域记录”。[JAVASCRIPT]
对于一个平台对象,其相关领域是其[[Realm]]字段的值。
然后,对于一个平台对象 o
,其相关设置对象是o
的相关领域的环境设置对象。
类似地,对于一个平台对象 o
,其相关全局对象是o
的相关领域的全局对象。
当以下所有条件为真时,对于一个环境设置对象 settings
,脚本被启用
settings
禁用脚本。(用户代理可能会为用户提供全局禁用脚本的选项,或者以更细粒度的级别禁用脚本,例如,按来源禁用,甚至可以细化到每个环境设置对象。)settings
的全局对象不是一个Window
对象,或者settings
的全局对象的关联的Document
的活动沙盒标志集没有设置其沙盒脚本浏览上下文标志。脚本被禁用对于一个环境设置对象,当脚本未启用时,即,当上述任何条件为假时。
脚本被启用对于一个节点node
,如果node
的节点文档的浏览上下文不为空,并且脚本被启用对于node
的相关设置对象。
脚本被禁用对于一个节点,当脚本未启用时,即,当其节点文档的浏览上下文为空,或者当脚本被禁用对于其相关设置对象。
一个环境 environment
是一个安全上下文,如果以下算法返回true
如果environment
是一个环境设置对象,那么
设global
为environment
的全局对象。
如果global
是一个WorkerGlobalScope
,那么
如果global
是一个WorkletGlobalScope
,那么返回true。
Worklet只能在安全上下文中创建。
如果URL是否可能值得信赖?在给定environment
的顶级创建URL的情况下返回“Potentially Trustworthy
”,那么返回true。
返回false。
一个脚本是两种可能的结构体之一(即,经典脚本或模块脚本)。所有脚本都具有
以下其中之一
一个源文本模块记录,对于JavaScript模块脚本;
一个WebAssembly模块记录,对于WebAssembly模块脚本;或者
null,表示解析失败。
一个JavaScript值,仅在记录为null时有意义,表示相应的脚本源文本无法解析。
一个JavaScript值,表示将阻止评估成功的错误。任何尝试运行脚本都将重新抛出此错误。
这可能是脚本的解析错误,但在模块脚本的情况下,它可能是其依赖项之一的解析错误,或来自解析模块说明符的错误。
由于此异常值由JavaScript规范提供,我们知道它永远不会为null,因此我们使用null来表示未发生错误。
null或用于解析模块说明符的基本URL。当不为null时,它将是获取脚本的URL(对于外部脚本),或包含文档的文档基本URL(对于内联脚本)。
一个布尔值,如果为true,则表示不会为此脚本中的错误提供错误信息。这用于为跨域脚本静音错误,因为这可能会泄漏私密信息。
模块脚本可以分为四种类型
如果模块脚本的记录是合成模块记录,并且它是通过创建CSS模块脚本算法创建的,则它是一个CSS模块脚本。CSS模块脚本表示已解析的CSS样式表。
如果模块脚本的记录是合成模块记录,并且它是通过创建JSON模块脚本算法创建的,则它是一个JSON模块脚本。JSON模块脚本表示已解析的JSON文档。
如果模块脚本的记录是WebAssembly模块记录,则它是一个WebAssembly模块脚本。
由于CSS样式表和JSON文档不导入依赖模块,并且在评估时不会抛出异常,因此CSS模块脚本和JSON模块脚本的获取选项和基本URL始终为null。
以下算法确定活动脚本
令record为GetActiveScriptOrModule()。
如果record为null,则返回null。
返回record.[[HostDefined]]。
活动脚本概念到目前为止仅由import()
功能使用,以确定用于解析相对模块说明符的基本URL。
本节介绍了一些用于获取脚本的算法,它们需要各种必要的输入,并生成经典或模块脚本。
用于初始获取和获取任何导入模块的加密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
令 newOptions 为 originalOptions 的副本。
令 integrity 为空字符串。
如果 settingsObject 的 全局对象 是一个 Window
对象,则将 integrity 设置为使用 url 和 settingsObject 解析模块完整性元数据 的结果。
将 newOptions 的 完整性元数据 设置为 integrity。
将 newOptions 的 获取优先级 设置为 "auto
"。
返回 newOptions。
为了 解析模块完整性元数据,给定一个 URL url 和一个 环境设置对象 settingsObject
返回 map 的 完整性[url]。
以下几种算法可以用 执行获取钩子 算法进行自定义,该算法接受一个 请求,一个布尔值 isTopLevel,以及一个 processCustomFetchResponse 算法。它使用一个 响应 和 null(失败)或包含响应体的 字节序列 来运行 processCustomFetchResponse。 isTopLevel 对所有 经典脚本 获取以及 获取外部模块脚本图 或 获取模块工作者脚本图 的初始获取为真,但对图中遇到的 import
语句或 import()
表达式导致的获取为假。
默认情况下,不提供 执行获取钩子 将导致以下算法简单地 获取 给定的 请求,并对 请求 进行算法特定的自定义,并对生成的 响应 进行验证。
为了在这些算法特定的自定义之上叠加你自己的自定义,请提供一个 执行获取钩子,它修改给定的 请求,获取 它,然后对生成的 响应 进行特定验证(如果验证失败,则使用 网络错误 完成)。
该钩子还可以用于执行更微妙的自定义,例如保留 响应 的缓存并完全避免执行 获取。
服务工作者 是使用其自己的钩子选项运行这些算法的规范示例。 [SW]
现在开始介绍算法本身。
为了 获取经典脚本,给定一个 URL url,一个 环境设置对象 settingsObject,一个 脚本获取选项 options,一个 CORS 设置属性状态 corsSetting,一个 编码 encoding,以及一个算法 onComplete,运行以下步骤。 onComplete 必须是一个接受 null(失败)或 经典脚本(成功)的算法。
令 request 为使用 url、"script
" 和 corsSetting 创建潜在的 CORS 请求 的结果。
将 request 的 客户端 设置为 settingsObject。
将 request 的 发起者类型 设置为 "script
"。
使用 request 和 options 设置经典脚本请求。
使用以下 processResponseConsumeBody 步骤 获取 request,给定 响应 response 和 null、失败或 字节序列 bodyBytes
response 可以是 CORS 同源 或 CORS 跨源。这只会影响错误报告的方式。
将 response 设置为 response 的 不安全响应。
如果以下任何条件为真
则运行 onComplete,给定 null,并中止这些步骤。
出于历史原因,此算法不像本节中的其他脚本获取算法那样包含 MIME 类型检查。
令 potentialMIMETypeForEncoding 为使用 response 的 标头列表 提取 MIME 类型 的结果。
将 encoding 设置为使用 potentialMIMETypeForEncoding 和 encoding 传统提取编码 的结果。
这有意忽略了 MIME 类型本质。
令 sourceText 为使用 encoding 作为备用编码,将 bodyBytes 解码为 Unicode 的 解码 结果。
解码 算法如果文件包含 BOM,则会覆盖 encoding。
如果 response 是 CORS 跨源,则令 mutedErrors 为真,否则为假。
令 script 为使用 sourceText、settingsObject、response 的 URL、options、mutedErrors 和 url 创建经典脚本 的结果。
为了 获取经典工作者脚本,给定一个 URL url,一个 环境设置对象 fetchClient,一个 目标 destination,一个 环境设置对象 settingsObject,一个算法 onComplete,以及一个可选的 执行获取钩子 performFetch,运行以下步骤。 onComplete 必须是一个接受 null(失败)或 经典脚本(成功)的算法。
令 request 为一个新的 请求,其 URL 为 url,客户端 为 fetchClient,目标 为 destination,发起类型 为 "other
",模式 为 "same-origin
",凭据模式 为 "same-origin
",解析器元数据 为 "not parser-inserted
",并且其 使用 URL 凭据标志 已设置。
如果 performFetch 被给出,则使用 request、true 和下面定义的 processResponseConsumeBody 运行 performFetch。
否则,获取 request,并将 processResponseConsumeBody 设置为下面定义的 processResponseConsumeBody。
在这两种情况下,对于给定 响应 response 和 null、失败或 字节序列 bodyBytes 的 processResponseConsumeBody,请执行以下算法
将 response 设置为 response 的 不安全响应。
如果以下任何条件为真
则运行 onComplete,给定 null,并中止这些步骤。
如果以下所有条件都为真
response 的 URL 的 方案 是 HTTP(S) 方案;并且
从 response 的 头列表 中 提取 MIME 类型 的结果不是 JavaScript MIME 类型,
则运行 onComplete,给定 null,并中止这些步骤。
出于历史上的 Web 兼容性原因,其他 获取方案 免于 MIME 类型检查。将来我们可能能够对此进行收紧;请参阅 问题 #3255。
令 sourceText 为 UTF-8 解码 bodyBytes 的结果。
令 script 为使用 sourceText、settingsObject、response 的 URL 和 默认脚本获取选项 创建经典脚本 的结果。
运行 onComplete,给定 script。
要 获取经典 worker 导入的脚本,请在给定 URL url、环境设置对象 settingsObject 和可选的 执行获取钩子 performFetch 的情况下运行这些步骤。该算法将在成功时返回一个 经典脚本,或者在失败时抛出异常。
令 response 为 null。
令 bodyBytes 为 null。
令 request 为一个新的 请求,其 URL 为 url,客户端 为 settingsObject,目标 为 "script
",发起类型 为 "other
",解析器元数据 为 "not parser-inserted
",并且其 使用 URL 凭据标志 已设置。
如果 performFetch 被给出,则使用 request、isTopLevel 和下面定义的 processResponseConsumeBody 运行 performFetch。
否则,获取 request,并将 processResponseConsumeBody 设置为下面定义的 processResponseConsumeBody。
在这两种情况下,对于给定 响应 res 和 null、失败或 字节序列 bb 的 processResponseConsumeBody,请执行以下算法
将 bodyBytes 设置为 bb。
将 response 设置为 res。
暂停 直到 response 不为 null 为止。
与本节中的其他算法不同,获取过程在此处是同步的。
将 response 设置为 response 的 不安全响应。
如果以下任何条件为真
bodyBytes 为 null 或失败;
从 response 的 头列表 中 提取 MIME 类型 的结果不是 JavaScript MIME 类型,
则抛出一个 "NetworkError
" DOMException
。
令 sourceText 为 UTF-8 解码 bodyBytes 的结果。
如果 response 是 CORS-跨域,则令 mutedErrors 为 true,否则为 false。
令 script 为给定 sourceText、settingsObject、response 的 URL、默认脚本获取选项 和 mutedErrors 创建经典脚本 的结果。
返回 script。
要 获取外部模块脚本图,请在给定 URL url、环境设置对象 settingsObject、脚本获取选项 options 和算法 onComplete 的情况下运行这些步骤。onComplete 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。
禁止进一步的导入映射,给定 settingsObject。
给定 url、settingsObject、"script
"、options、settingsObject、"client
"、true 和以下步骤(给定 result),获取单个模块脚本。
如果 result 为 null,则使用 null 运行 onComplete,并中止这些步骤。
给定 settingsObject、"script
" 和 onComplete,获取并链接 result 的后代。
要 获取 modulepreload 模块脚本图,请在给定 URL url、目标 destination、环境设置对象 settingsObject、脚本获取选项 options 和算法 onComplete 的情况下运行这些步骤。onComplete 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。
禁止进一步的导入映射,给定 settingsObject。
给定 url、settingsObject、destination、options、settingsObject、"client
"、true 和以下步骤(给定 result),获取单个模块脚本。
使用 result 运行 onComplete。
如果 result 不为 null,则可以选择 获取并链接 result 的后代,给定 settingsObject、destination 和一个空算法。
通常,执行此步骤将有利于性能,因为它允许预加载将不可避免地稍后通过算法(如 获取外部模块脚本图 获取整个图)请求的模块。但是,用户代理可能希望在带宽受限的情况下或相关获取已经在进行的情况下跳过它们。
要 获取内联模块脚本图,请在给定 字符串 sourceText、URL baseURL、环境设置对象 settingsObject、脚本获取选项 options 和算法 onComplete 的情况下运行这些步骤。onComplete 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。
禁止进一步的导入映射,给定 settingsObject。
令 script 为使用 sourceText、settingsObject、baseURL 和 options 创建 JavaScript 模块脚本 的结果。
给定 settingsObject、"script
" 和 onComplete,获取并链接 script 的后代。
给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 凭证模式 credentialsMode、一个 环境设置对象 settingsObject 和一个算法 onComplete,获取工作线程/模块工作线程脚本图,给定 url、fetchClient、destination、credentialsMode、settingsObject 和 onComplete。
给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 凭证模式 credentialsMode、一个 环境设置对象 settingsObject、一个 模块响应映射 moduleResponsesMap 和一个算法 onComplete,获取工作线程/模块工作线程脚本图,给定 url、fetchClient、destination、credentialsMode、settingsObject、onComplete 和以下 执行获取钩子,给定 request 和 processCustomFetchResponse。
令 requestURL 为 request 的 URL。
如果 moduleResponsesMap[requestURL] 为 "fetching
",则 并行等待 直到该条目的值发生变化,然后在 网络任务源 上 排队一个任务 以继续执行以下步骤。
如果 moduleResponsesMap[requestURL] 存在,则
令 cached 为 moduleResponsesMap[requestURL]。
使用 cached[0] 和 cached[1] 运行 processCustomFetchResponse。
返回。
设置 moduleResponsesMap[requestURL] 为 "fetching
"。
获取 request,并将 processResponseConsumeBody 设置为以下步骤,给定 响应 response 和 null、失败或一个 字节序列 bodyBytes
设置 moduleResponsesMap[requestURL] 为 (response,bodyBytes)。
使用 response 和 bodyBytes 运行 processCustomFetchResponse。
以下算法仅供本规范内部使用,作为 获取外部模块脚本图 或其他类似概念的一部分,其他规范不应直接使用它们。
此图说明了这些算法与上面算法以及彼此之间的关系
给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 凭证模式 credentialsMode、一个 环境设置对象 settingsObject、一个算法 onComplete 和一个可选的 执行获取钩子 performFetch,运行这些步骤。 onComplete 必须是一个接受 null(失败)或 模块脚本(成功)的算法。
令 options 为一个 脚本获取选项,其 加密 nonce 为空字符串,完整性元数据 为空字符串,解析器元数据 为 "not-parser-inserted
",凭证模式 为 credentialsMode,referrer 策略 为空字符串,获取优先级 为 "auto
"。
获取单个模块脚本,给定 url、fetchClient、destination、options、settingsObject、"client
"、true 和 onSingleFetchComplete,如下定义。如果给定 performFetch,则将其一同传递。
onSingleFetchComplete 给定 result 为以下算法
如果 result 为 null,则使用 null 运行 onComplete,并中止这些步骤。
获取并链接 result 的后代,给定 fetchClient、destination 和 onComplete。如果给定 performFetch,则将其一同传递。
给定一个 模块脚本 moduleScript、一个 环境设置对象 fetchClient、一个 目标 destination、一个算法 onComplete 和一个可选的 执行获取钩子 performFetch,获取并链接 它的后代,运行这些步骤。 onComplete 必须是一个接受 null(失败)或 模块脚本(成功)的算法。
令 record 为 moduleScript 的 记录。
如果 record 为 null,则
令 state 为 Record { [[ParseError]]: null, [[Destination]]: destination, [[PerformFetch]]: null, [[FetchClient]]: fetchClient }。
如果给定 performFetch,则将 state.[[PerformFetch]] 设置为 performFetch。
令 loadingPromise 为 record.LoadRequestedModules(state)。
此步骤将递归地加载所有模块传递依赖项。
如果 state.[[ParseError]] 不为 null,则将 moduleScript 的 要重新抛出的错误 设置为 state.[[ParseError]] 并使用 moduleScript 运行 onComplete。
否则,使用 null 运行 onComplete。
当 loadingPromise 由于加载错误而被拒绝时,state.[[ParseError]] 为 null。
给定一个 URL url、一个 环境设置对象 fetchClient、一个 目标 destination、一个 脚本获取选项 options、一个 环境设置对象 settingsObject、一个 referrer referrer、一个可选的 ModuleRequest 记录 moduleRequest、一个布尔值 isTopLevel、一个算法 onComplete 和一个可选的 执行获取钩子 performFetch,获取单个模块脚本,运行这些步骤。 onComplete 必须是一个接受 null(失败)或 模块脚本(成功)的算法。
令 moduleType 为 "javascript-or-wasm
"。
如果给定 moduleRequest,则将 moduleType 设置为使用给定的 moduleRequest 运行 来自模块请求的模块类型 步骤的结果。
断言:使用给定的 moduleType 和 settingsObject 运行 模块类型是否允许 步骤的结果为 true。否则,我们将不会到达此点,因为在 HostLoadImportedModule 或 获取单个导入的模块脚本 中检查 moduleRequest.[[Attributes]] 时会引发失败。
令 moduleMap 为 settingsObject 的 模块映射。
如果 moduleMap[(url,moduleType)] 为 "fetching
",则 并行等待 直到该条目的值发生变化,然后在 网络任务源 上 排队一个任务 以继续执行以下步骤。
如果 moduleMap[(url,moduleType)] 存在,则使用 moduleMap[(url,moduleType)] 运行 onComplete 并返回。
设置 moduleMap[(url,moduleType)] 为 "fetching
"。
令 request 为一个新的 请求,其 URL 为 url,模式 为 "cors
",referrer 为 referrer,客户端 为 fetchClient。
将 request 的 目标 设置为使用给定的 destination 和 moduleType 运行 来自模块类型的获取目标 步骤的结果。
如果 `destination` 是 "worker
"、"sharedworker
" 或 "serviceworker
",并且 `isTopLevel` 为真,则将 `request` 的 模式 设置为 "same-origin
"。
将 `request` 的 发起者类型 设置为 "script
"。
设置模块脚本请求,给定 `request` 和 `options`。
如果 performFetch 被给出,则使用 request、isTopLevel 和下面定义的 processResponseConsumeBody 运行 performFetch。
否则,获取 `request`,其中 `processResponseConsumeBody` 设置为 `processResponseConsumeBody`,如下定义。
在这两种情况下,令给定 响应 `response` 和 null、失败或 字节序列 `bodyBytes` 的 `processResponseConsumeBody` 为以下算法
response 始终是 CORS-同源。
如果以下任何条件为真
然后 设置 `moduleMap[(url, moduleType)]` 为 null,运行给定 null 的 `onComplete`,并中止这些步骤。
令 `mimeType` 为从 response 的 标题列表 中 提取 MIME 类型 的结果。
令 `moduleScript` 为 null。
令 `referrerPolicy` 为给定 response 的 解析 `Referrer-Policy
` 标题 的结果。 [REFERRERPOLICY]
如果 `referrerPolicy` 不是空字符串,则将 `options` 的 推荐人策略 设置为 `referrerPolicy`。
如果 `mimeType` 的 本质 是 "application/wasm
" 并且 `moduleType` 是 "javascript-or-wasm
",则将 `moduleScript` 设置为给定 `bodyBytes`、`settingsObject`、`response` 的 URL 和 `options` 的 创建 WebAssembly 模块脚本 的结果。
否则
令 `sourceText` 为 UTF-8 解码 `bodyBytes` 的结果。
如果 `mimeType` 是 JavaScript MIME 类型 并且 `moduleType` 是 "javascript-or-wasm
",则将 `moduleScript` 设置为给定 `sourceText`、`settingsObject`、`response` 的 URL 和 `options` 的 创建 JavaScript 模块脚本 的结果。
如果 `mimeType` 的 MIME 类型本质 是 "text/css
" 并且 `moduleType` 是 "css
",则将 `moduleScript` 设置为给定 `sourceText` 和 `settingsObject` 的 创建 CSS 模块脚本 的结果。
如果 `mimeType` 是 JSON MIME 类型 并且 `moduleType` 是 "json
",则将 `moduleScript` 设置为给定 `sourceText` 和 `settingsObject` 的 创建 JSON 模块脚本 的结果。
设置 `moduleMap[(url, moduleType)]` 为 `moduleScript`,并运行给定 `moduleScript` 的 `onComplete`。
有意的是,模块映射 采用 请求 URL 作为键,而 基本 URL 则为 模块脚本 设置为 响应 URL。前者用于消除获取重复项,而后者用于 URL 解析。
为了 获取单个导入的模块脚本,给定一个 URL `url`、一个 环境设置对象 `fetchClient`、一个 目标 `destination`、一个 脚本获取选项 `options`、环境设置对象 `settingsObject`、一个 推荐人 `referrer`、一个 ModuleRequest 记录 `moduleRequest`、一个算法 `onComplete` 和一个可选的 执行获取钩子 `performFetch`,运行这些步骤。`onComplete` 必须是一个接受 null(失败时)或 模块脚本(成功时)的算法。
断言:`moduleRequest.[[Attributes]]` 不包含任何 记录 `entry`,使得 `entry.[[Key]]` 不是 "type
",因为我们只在 HostGetSupportedImportAttributes 中请求了 "type
" 属性。
令 `moduleType` 为运行给定 `moduleRequest` 的 模块类型来自模块请求 步骤的结果。
如果运行给定 `moduleType` 和 `settingsObject` 的 模块类型允许 步骤的结果为 false,则运行给定 null 的 `onComplete`,并返回。
获取单个模块脚本,给定 `url`、`fetchClient`、`destination`、`options`、`settingsObject`、`referrer`、`moduleRequest`、false 和 `onComplete`。如果给出了 `performFetch`,也将其传递。
为了 创建经典脚本,给定一个 字符串 `source`、一个 环境设置对象 `settings`、一个 URL `baseURL`、一个 脚本获取选项 `options`、一个可选的布尔值 `mutedErrors`(默认值为 false)和一个可选的 URL-或-null `sourceURLForWindowScripts`(默认值为 null)
如果 `mutedErrors` 为真,则将 `baseURL` 设置为 "about:blank
"。
当 `mutedErrors` 为真时,`baseURL` 是脚本的 CORS-跨源 响应 的 url,它不应暴露给 JavaScript。因此,`baseURL` 在此处被清理。
如果 脚本被禁用 用于 `settings`,则将 `source` 设置为空字符串。
令 `script` 为一个新的 经典脚本,该算法将随后初始化。
将 `script` 的 设置对象 设置为 `settings`。
将 `script` 的 基本 URL 设置为 `baseURL`。
将 `script` 的 获取选项 设置为 `options`。
将 `script` 的 静音错误 设置为 `mutedErrors`。
记录经典脚本创建时间,给定 `script` 和 `sourceURLForWindowScripts`。
令 `result` 为 ParseScript(`source`,`settings` 的 领域,`script`)。
将 `script` 作为最后一个参数传递到这里可确保 `result.[[HostDefined]]` 将为 `script`。
如果 `result` 是一个 列表 错误,则
将 `script` 的 记录 设置为 `result`。
返回 script。
为了 创建 JavaScript 模块脚本,给定一个 字符串 `source`、一个 环境设置对象 `settings`、一个 URL `baseURL` 和一个 脚本获取选项 `options`
如果 脚本被禁用 用于 `settings`,则将 `source` 设置为空字符串。
令 `script` 为一个新的 模块脚本,该算法将随后初始化。
将 `script` 的 设置对象 设置为 `settings`。
将 `script` 的 基本 URL 设置为 `baseURL`。
将 `script` 的 获取选项 设置为 `options`。
令 `result` 为 ParseModule(`source`,`settings` 的 领域,`script`)。
将 `script` 作为最后一个参数传递到这里可确保 `result.[[HostDefined]]` 将为 `script`。
如果 `result` 是一个 列表 错误,则
将 script 的 解析错误 设置为 result[0]。
返回 script。
将 script 的 记录 设置为 result。
返回 script。
要 创建一个 WebAssembly 模块脚本,给定一个 字节序列 bodyBytes,一个 环境设置对象 settings,一个 URL baseURL,以及一个 脚本获取选项 options
如果 脚本被禁用 用于 settings,则将 bodyBytes 设置为字节序列 0x00 0x61 0x73 0x6d 0x01 0x00 0x00 0x00。
此字节序列对应于一个空的 WebAssembly 模块,它只包含魔数和版本号。
让 script 是一个新的 模块脚本,该算法随后将对其进行初始化。
将 script 的 设置对象 设置为 settings。
将 script 的 基本 URL 设置为 baseURL。
将 script 的 获取选项 设置为 options。
让 result 是 解析 WebAssembly 模块 的结果,给定 bodyBytes,settings 的 领域,以及 script。
将 `script` 作为最后一个参数传递到这里可确保 `result.[[HostDefined]]` 将为 `script`。
如果前一步抛出了一个错误 error,则
将 script 的 解析错误 设置为 error。
返回 script。
将 script 的 记录 设置为 result。
返回 script。
WebAssembly JavaScript 接口:ESM 集成 指定了 WebAssembly 与 ECMA-262 模块加载集成的钩子。这包括对直接依赖项导入的支持,以及对源阶段导入的支持,该阶段支持虚拟化和多实例化。[WASMESM]
要 创建一个 CSS 模块脚本,给定一个字符串 source 和一个 环境设置对象 settings
让 script 是一个新的 模块脚本,该算法随后将对其进行初始化。
将 script 的 设置对象 设置为 settings。
让 sheet 是运行步骤以 创建一个构造的 CSSStyleSheet
的结果,其参数为空字典。
运行步骤以 同步替换 CSSStyleSheet
的规则,在 sheet 上给定 source。
如果这抛出了异常,则捕获它,将 script 的 解析错误 设置为该异常,并返回 script。
步骤以 同步替换 CSSStyleSheet
的规则 将在 source 包含任何 @import
规则时抛出异常。这是目前的设计,因为关于如何处理 CSS 模块脚本的这些规则还没有达成一致;因此,在达成共识之前,它们完全被阻止。
将 script 的 记录 设置为 CreateDefaultExportSyntheticModule(sheet) 的结果。
返回 script。
要 创建一个 JSON 模块脚本,给定一个字符串 source 和一个 环境设置对象 settings
让 script 是一个新的 模块脚本,该算法随后将对其进行初始化。
将 script 的 设置对象 设置为 settings。
让 result 是 ParseJSONModule(source)。
如果这抛出了异常,则捕获它,将 script 的 解析错误 设置为该异常,并返回 script。
将 script 的 记录 设置为 result。
返回 script。
给定一个 ModuleRequest 记录 moduleRequest,模块类型来自模块请求 步骤如下
令 moduleType 为 "javascript-or-wasm
"。
如果 moduleRequest.[[Attributes]] 具有一个 记录 entry,使得 entry.[[Key]] 是 "type
",则
如果 entry.[[Value]] 是 "javascript-or-wasm
",则将 moduleType 设置为 null。
本规范在内部使用 "javascript-or-wasm
" 模块类型来表示 JavaScript 模块脚本 或 WebAssembly 模块脚本,因此需要此步骤来防止模块使用 "javascript-or-wasm
" 类型属性导入(一个为 null 的 moduleType 将导致 允许的模块类型 检查失败)。
否则,将 moduleType 设置为 entry.[[Value]]。
返回 moduleType。
给定一个 字符串 moduleType 和一个 环境设置对象 settings,允许的模块类型 步骤如下
如果 moduleType 不是 "javascript-or-wasm
"、"css
" 或 "json
",则返回 false。
如果 moduleType 是 "css
" 并且 CSSStyleSheet
接口在 settings 的 领域 中 未公开,则返回 false。
返回 true。
给定一个 目标 defaultDestination 和一个 字符串 moduleType,获取目标来自模块类型 步骤如下
json
",则返回 "json
"。css
",则返回 "style
"。要 运行一个经典脚本,给定一个 经典脚本 script 和一个可选的布尔值 rethrow errors(默认值为 false)
让 settings 是 script 的 设置对象。
检查我们是否可以运行脚本,使用 settings。如果这返回 "不运行",则返回 NormalCompletion(empty)。
记录经典脚本执行开始时间,给定 script。
准备运行脚本,给定 settings。
让 evaluationStatus 为 null。
如果 script 的 需要重新抛出的错误 不为 null,则将 evaluationStatus 设置为 Completion { [[Type]]: throw, [[Value]]: script 的 需要重新抛出的错误, [[Target]]: empty }。
否则,将 evaluationStatus 设置为 ScriptEvaluation(script 的 记录)。
如果 ScriptEvaluation 未完成,因为用户代理 中止了正在运行的脚本,则将 evaluationStatus 保持为 null。
如果 evaluationStatus 是一个 异常完成,则
如果 rethrow errors 为 true 并且 script 的 静音错误 为 false,则
清理运行脚本后的操作,使用 settings。
重新抛出 evaluationStatus.[[Value]]。
如果 rethrow errors 为 true 并且 script 的 静音错误 为 true,则
清理运行脚本后的操作,使用 settings。
抛出一个 "NetworkError
" DOMException
。
否则,rethrow errors 为 false。执行以下步骤
报告异常,由 evaluationStatus.[[Value]] 提供,用于 script 的 设置对象 的 全局对象。
清理运行脚本后的操作,使用 settings。
返回 evaluationStatus。
清理运行脚本后的操作,使用 settings。
如果 evaluationStatus 是一个正常完成,则返回 evaluationStatus。
如果我们已经到达这一步,evaluationStatus 将保持为 null,因为脚本在评估期间被 过早中止。返回 Completion { [[Type]]: throw, [[Value]]: 新的 "QuotaExceededError
" DOMException
, [[Target]]: 空 }。
要 运行模块脚本,给定一个 模块脚本 script 和一个可选的布尔值 preventErrorReporting(默认值为 false)
令 settings 为 script 的 设置对象。
检查我们是否可以运行脚本,使用 settings。如果这返回 "do not run",则返回 一个解析为 undefined 的 Promise。
记录模块脚本执行开始时间,给定 script。
准备运行脚本,给定 settings。
令 evaluationPromise 为 null。
如果 script 的 要重新抛出的错误 不为 null,则将 evaluationPromise 设置为 一个被 script 的 要重新抛出的错误 拒绝的 Promise。
否则
令 record 为 script 的 记录。
将 evaluationPromise 设置为 record.Evaluate()。
此步骤将递归评估模块的所有依赖项。
如果 Evaluate 由于用户代理 中止运行脚本 而无法完成,则将 evaluationPromise 设置为 一个被 新的 "QuotaExceededError
" DOMException
拒绝的 Promise。
如果 preventErrorReporting 为 false,则 在 evaluationPromise 被 reason 拒绝时,报告一个异常,该异常由 reason 为 script 的 设置对象 的 全局对象 提供。
清理运行脚本后的操作,使用 settings。
返回 evaluationPromise。
使用 环境设置对象 settings 检查我们是否可以运行脚本 的步骤如下。它们返回 "run" 或 "do not run"。
如果 settings 指定的 全局对象 是一个 Window
对象,其 Document
对象不是 完全活动,则返回 "do not run"。
如果 脚本被禁用,针对 settings,则返回 "do not run"。
返回 "run"。
使用 环境设置对象 settings 准备运行脚本 的步骤如下
将 settings 的 领域执行上下文 推入 JavaScript 执行上下文栈;它现在是 正在运行的 JavaScript 执行上下文。
将 settings 添加到 周围代理 的 事件循环 的 当前正在运行的任务 的 脚本评估环境设置对象集。
使用 环境设置对象 settings 清理运行脚本后的操作 的步骤如下
断言:settings 的 领域执行上下文 是 正在运行的 JavaScript 执行上下文。
从 JavaScript 执行上下文栈 中删除 settings 的 领域执行上下文。
如果 JavaScript 执行上下文栈 现在为空,执行微任务检查点。(如果这运行脚本,这些算法将被重新进入调用。)
这些算法不是由一个脚本直接调用另一个脚本来调用的,但它们可以以间接的方式被重新进入调用,例如,如果一个脚本调度了一个事件,并且该事件注册了事件监听器。
正在运行的脚本 是 脚本,位于 正在运行的 JavaScript 执行上下文 的 ScriptOrModule 组件的 [[HostDefined]] 字段中。
虽然 JavaScript 规范没有考虑这种可能性,但有时有必要 中止运行脚本。这会导致任何 ScriptEvaluation 或 Source Text Module Record 的 Evaluate 调用立即停止,清空 JavaScript 执行上下文栈,而不会触发任何正常机制,如 finally
块。 [JAVASCRIPT]
用户代理可能会对脚本施加资源限制,例如 CPU 配额、内存限制、总执行时间限制或带宽限制。当脚本超出限制时,用户代理可以抛出 "QuotaExceededError
" DOMException
,中止脚本 而不抛出异常,提示用户,或限制脚本执行。
例如,以下脚本永远不会终止。用户代理可以在等待几秒钟后,提示用户要么终止脚本,要么让它继续。
< script >
while ( true ) { /* loop */ }
</ script >
鼓励用户代理允许用户在脚本提示用户(例如,使用 window.alert()
API)或由于脚本的操作(例如,因为脚本超出了时间限制)时,禁用脚本。
如果脚本在执行期间被禁用,则应立即终止脚本。
用户代理可以允许用户专门禁用脚本,仅用于关闭 浏览上下文 的目的。
例如,上面示例中提到的提示还可以向用户提供一种机制,可以完全关闭页面,而无需运行任何 unload
事件处理程序。
在所有当前引擎中支持。
self.reportError(e)
在给定值 e 的全局对象上调度一个 error
事件,方式与未捕获的异常相同。
要从 JavaScript 值 exception 中 提取错误信息
令 attributes 为一个空的 映射,按键为 IDL 属性。
将 attributes[error
] 设置为 exception。
将 attributes[message
]、attributes[filename
]、attributes[lineno
] 和 attributes[colno
] 设置为从 exception 中派生的 实现定义的 值。
浏览器实现这里或 JavaScript 规范中未指定的行为,以收集有用的值,包括在异常情况下(例如,eval
)。将来,这可能会被更详细地指定。
返回 attributes。
要针对特定 全局对象 global 和可选布尔值 omitError(默认值为 false)报告一个异常 exception,该异常是一个 JavaScript 值
令 notHandled 为 true。
令 errorInfo 为从 exception 中 提取错误信息 的结果。
令 script 为一个 脚本,该脚本以 实现定义的 方式找到,或为 null。这通常应该是 正在运行的脚本(最显著的是在 运行经典脚本 期间)。
对于不太常见的情况,各个实现尚未就用于确定是否静音错误的脚本使用达成一致的可互操作行为。
如果 script 是一个 经典脚本 且 script 的 静音错误 为 true,则将 errorInfo[error
] 设置为 null,errorInfo[message
] 设置为 "Script error.
",errorInfo[filename
] 设置为空字符串,errorInfo[lineno
] 设置为 0,errorInfo[colno
] 设置为 0。
如果 omitError 为 true,则将 errorInfo[error
] 设置为 null。
如果 global 不是 处于错误报告模式,则
如果 global 实现 EventTarget
,则将 notHandled 设置为在 global 上 触发一个名为 error
的事件的结果,使用 ErrorEvent
,其中 cancelable
属性初始化为 true,其他属性根据 errorInfo 初始化。
在事件处理程序中返回 true 会根据 事件处理程序处理算法 取消事件。
将 global 的 处于错误报告模式 设置为 false。
如果 notHandled 为 true,则
将 errorInfo[error
] 设置为 null。
如果 global 实现 DedicatedWorkerGlobalScope
,在 global 关联的 Worker
的 相关全局对象 上,DOM 操作任务源 上排队一个全局任务,以执行以下步骤
令 workerObject 为与 global 关联的 Worker
对象。
将 notHandled 设置为在 workerObject 上 触发一个名为 error
的事件的结果,使用 ErrorEvent
,其中 cancelable
属性初始化为 true,其他属性根据 errorInfo 初始化。
如果 notHandled 为 true,则 报告 exception,针对 workerObject 的 相关全局对象,将 omitError 设置为 true。
实际的 exception 值在拥有者领域将不可用,但用户代理仍然会传达足够的信息来设置消息、文件名和其他属性,以及可能向开发者控制台报告。
否则,用户代理可能会向开发者控制台报告 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
[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。在适当的地方,它被设置为表示错误的对象(例如,在未捕获异常的情况下,为异常对象)。
在所有当前引擎中支持。
除了同步 运行时脚本错误 外,脚本还会遇到异步 Promise 拒绝,通过 unhandledrejection
和 rejectionhandled
事件进行跟踪。通过 HostPromiseRejectionTracker 抽象操作来跟踪这些拒绝,但它们的报告在此处定义。
要 通知关于被拒绝的 Promise,给定 全局对象 global
令 list 为 global 的 即将被通知的被拒绝的 Promise 列表 的 克隆。
如果 list 为空,则返回。
清空 global 的 即将被通知的被拒绝的 Promise 列表。
在 global 上,DOM 操作任务源 上排队一个全局任务,以执行以下步骤
对于 list 中的每个 Promise p
如果 p.[[PromiseIsHandled]] 为 true,则 继续。
令 notCanceled 为在 global 上 触发一个名为 unhandledrejection
的事件的结果,使用 PromiseRejectionEvent
,其中 cancelable
属性初始化为 true,promise
属性初始化为 p,reason
属性初始化为 p.[[PromiseResult]]。
如果 notCanceled 为 true,则用户代理可能会向开发者控制台报告 p.[[PromiseResult]]。
如果 p.[[PromiseIsHandled]] 为 false,则 将 p 追加 到 global 的 未处理的被拒绝的 Promise 弱集合。
在所有当前引擎中支持。
接口定义如下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 ;
};
在所有当前引擎中支持。
promise
属性必须返回其初始化的值。它表示此通知所针对的 Promise。
由于 Web IDL 针对 Promise<T>
类型的转换规则始终将输入包装到一个新的 Promise 中,因此
属性的类型为 promise
,更适合表示对原始 Promise 对象的不透明句柄。object
在所有当前引擎中支持。
reason
属性必须返回其初始化的值。它表示 promise 的拒绝原因。
一个 导入映射解析结果 是一个类似于 脚本 的 结构体,也可以存储在 script
元素的 结果 中,但对于其他目的不计入 脚本。它具有以下 项
要 创建导入映射解析结果,给定一个 字符串 input 和一个 URL baseURL
给定 input 和 baseURL 解析导入映射字符串,捕获任何异常。如果这抛出了异常,则将 result 的 要重新抛出的错误 设置为该异常。否则,将 result 的 导入映射 设置为返回值。
返回 result。
要 注册导入映射,给定一个 Window
global 和一个 导入映射解析结果 result
该 解析模块标识符 算法是将模块标识符字符串转换为 URL 的主要入口点。当没有涉及 导入映射 时,它相对简单,并且简化为 解析 URL 样式的模块标识符。
当存在一个非空的 导入映射 时,行为更加复杂。它检查所有适用 模块标识符映射 中的候选条目,从最特定到最不特定的 范围(回退到顶级无范围 导入),以及从最特定到最不特定的前缀。对于每个候选条目,解析导入匹配 算法将给出以下结果
最后,如果通过任何候选 模块标识符映射 都没有找到成功的解析,解析模块标识符 将抛出一个异常。因此,结果始终是一个 URL 或一个抛出的异常。
要 解析模块标识符,给定一个 script-或-null referringScript 和一个 字符串 specifier
令 settingsObject 和 baseURL 为 null。
如果 referringScript 不为 null,则
否则
将 settingsObject 设置为 当前设置对象。
将 baseURL 设置为 settingsObject 的 API 基本 URL。
令 importMap 为一个 空导入映射。
如果 settingsObject 的 全局对象 实现 Window
,则将 importMap 设置为 settingsObject 的 全局对象 的 导入映射。
令 baseURLString 为 baseURL,序列化。
令 asURL 为给定 specifier 和 baseURL 的 解析 URL 样式的模块标识符 的结果。
令 normalizedSpecifier 为 asURL 的 序列化,如果 asURL 不为 null;否则,specifier。
令 topLevelImportsMatch 为给定 normalizedSpecifier、asURL 和 importMap 的 导入 的 解析导入匹配 的结果。
如果 topLevelImportsMatch 不为 null,则返回 topLevelImportsMatch。
此时,specifier 没有被 importMap 重新映射到任何内容,但它可能能够被转换为 URL。
如果 asURL 不为 null,则返回 asURL。
抛出一个 TypeError
,指示 specifier 是一个裸标识符,但没有被 importMap 重新映射到任何内容。
要 解析导入匹配,给定一个 字符串 normalizedSpecifier、一个 URL-或-null asURL 和一个 模块标识符映射 specifierMap
对于每个 specifierKey → resolutionResult 的 specifierMap
如果 specifierKey 为 normalizedSpecifier,则
如果以下所有条件都为真
specifierKey 以 U+002F (/) 结尾;
specifierKey 是 normalizedSpecifier 的 代码单元前缀;并且
要么 asURL 为 null,要么 asURL 是特殊的
则
如果 resolutionResult 为 null,则抛出一个 TypeError
,指示 specifierKey 的解析被 null 条目阻止。
这将终止整个 解析模块标识符 算法,没有任何进一步的回退。
令 afterPrefix 为 normalizedSpecifier 中初始 specifierKey 前缀后的部分。
令 url 为 afterPrefix 使用 resolutionResult 的 URL 解析 的结果。
如果 url 为失败,则抛出一个 TypeError
,指示 normalizedSpecifier 的解析被阻止,因为 afterPrefix 部分无法相对于 specifierKey 前缀映射到的 resolutionResult 进行 URL 解析。
这将终止整个 解析模块标识符 算法,没有任何进一步的回退。
如果resolutionResult的序列化不是url的序列化的代码单元前缀,则抛出一个TypeError
,指示normalizedSpecifier的解析由于回溯到其前缀specifierKey之上而被阻止。
这将终止整个解析模块说明符算法,不再进行任何回退。
返回url。
返回null。
如果可能的话,解析模块说明符算法将回退到不太具体的范围,或回退到“imports
”。
为了解析类似 URL 的模块说明符,给定一个字符串specifier和一个URLbaseURL
如果specifier以“/
”,“./
”或“../
”开头,那么
让url成为URL 解析specifier与baseURL的结果。
如果url失败,则返回null。
这可能发生的一种情况是,如果specifier是“../foo
”,而baseURL是data:
URL。
返回url。
这包括specifier以“//
”开头的情况,即方案相关的 URL。因此,url最终可能与baseURL具有不同的主机。
让url成为URL 解析specifier(没有基本 URL)的结果。
如果url失败,则返回null。
返回url。
一个导入映射允许控制模块说明符解析。导入映射通过内联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"
将具有不同的含义,具体取决于哪个引用脚本包含该语句
在位于/a/
下的脚本中,这将导入/node_modules/moment/src/moment.js
。
在位于/b/
下的脚本中,这将导入https://cdn.example.com/moment/src/moment.js
。
在位于/c/
下的脚本中,这将无法解析,因此将抛出异常。
范围的典型用法是允许多个版本的“相同”模块存在于 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。 [JSON]
JSON 必须表示一个 JSON 对象,最多包含三个键“imports
”,“scopes
”和“integrity
”。
如果存在,则对应于“imports
”,“scopes
”和“integrity
”键的值本身必须是 JSON 对象。
如果存在,则对应于“imports
”键的值必须是一个有效的模块说明符映射。
如果存在,则对应于“scopes
”键的值必须是一个 JSON 对象,其键是有效的 URL 字符串,其值是有效的模块说明符映射。
如果存在,则对应于“integrity
”键的值必须是一个 JSON 对象,其键是有效的 URL 字符串,其值符合完整性属性的要求。
一个有效的模块说明符映射是一个满足以下要求的 JSON 对象
它的所有键都必须是非空的。
它的所有值都必须是字符串。
每个值必须是有效的绝对 URL或有效的 URL 字符串,该字符串以“/
”,“./
”或“../
”开头。
如果给定的键以“/
”结尾,则其对应值也必须以“/
”结尾。
一个模块说明符映射是一个有序映射,其键是字符串,其值是URL或null。
一个 模块完整性映射 是一个 有序映射,其 键 是 URL,其 值 是 字符串,这些字符串将用作 完整性元数据。
一个 空导入映射 是一个 导入映射,其 导入 和 范围 都是空映射。
每个 Window
都有一个 导入映射,最初是一个 空导入映射。
每个 Window
都有一个 允许导入映射 布尔值,最初为 true。
要 禁止进一步导入映射,给定一个 环境设置对象 settingsObject
目前,一旦任何模块加载开始,或者一旦加载了单个导入映射,导入映射就会被禁止。这些限制可能会在未来的规范修订中被解除。
要 解析导入映射字符串,给定一个 字符串 input 和一个 URL baseURL
让 parsed 是给定 input 的 将 JSON 字符串解析为 Infra 值 的结果。
让 sortedAndNormalizedImports 是一个空的 有序映射。
如果 parsed["imports
"] 存在,则
如果 parsed["imports
"] 不是一个 有序映射,则抛出一个 TypeError
,表明 "imports
" 顶层键的值需要是 JSON 对象。
将 sortedAndNormalizedImports 设置为给定 parsed["imports
"] 和 baseURL 的 对模块说明符映射进行排序和规范化 的结果。
让 sortedAndNormalizedScopes 是一个空的 有序映射。
如果 parsed["scopes
"] 存在,则
如果 parsed["scopes
"] 不是一个 有序映射,则抛出一个 TypeError
,表明 "scopes
" 顶层键的值需要是 JSON 对象。
将 sortedAndNormalizedScopes 设置为给定 parsed["scopes
"] 和 baseURL 的 对范围进行排序和规范化 的结果。
让 normalizedIntegrity 是一个空的 有序映射。
如果 parsed["integrity
"] 存在,则
如果 parsed["integrity
"] 不是一个 有序映射,则抛出一个 TypeError
,表明 "integrity
" 顶层键的值需要是 JSON 对象。
将 normalizedIntegrity 设置为给定 parsed["integrity
"] 和 baseURL 的 对模块完整性映射进行规范化 的结果。
如果 parsed 的 键 包含 除了 "imports
"、"scopes
" 或 "integrity
" 之外的任何项目,则用户代理应该 向控制台报告警告,表明在导入映射中存在无效的顶层键。
这可以帮助检测拼写错误。这不是错误,因为这会阻止将来任何扩展以向后兼容的方式添加。
返回一个 导入映射,其 导入 是 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
让 normalized 是一个空的 有序映射。
对于每个 specifierKey → value 的 originalMap
让 normalizedSpecifierKey 是给定 specifierKey 和 baseURL 的 对说明符键进行规范化 的结果。
如果 normalizedSpecifierKey 为 null,则 继续。
如果 value 不是一个 字符串,则
让 addressURL 是给定 value 和 baseURL 的 解析类似 URL 的模块说明符 的结果。
如果 addressURL 为 null,则
如果 specifierKey 以 U+002F (/) 结尾,并且 addressURL 的 序列化 不以 U+002F (/) 结尾,则
将 normalized[normalizedSpecifierKey] 设置为 addressURL。
返回 按降序排序 normalized 的结果,如果条目 a 的 键 按代码单元小于 条目 b 的 键,则条目 a 小于条目 b。
要 对范围进行排序和规范化,给定一个 有序映射 originalMap 和一个 URL baseURL
让 normalized 是一个空的 有序映射。
对于每个 scopePrefix → potentialSpecifierMap 的 originalMap
如果 potentialSpecifierMap 不是一个 有序映射,则抛出一个 TypeError
,表明具有前缀 scopePrefix 的范围的值需要是 JSON 对象。
让 scopePrefixURL 是使用 baseURL 解析 URL scopePrefix 的结果。
如果 scopePrefixURL 为失败,则
让 normalizedScopePrefix 是 scopePrefixURL 的 序列化。
将 normalized[normalizedScopePrefix] 设置为给定 potentialSpecifierMap 和 baseURL 的 对模块说明符映射进行排序和规范化 的结果。
返回 按降序排序 normalized 的结果,如果条目 a 的 键 按代码单元小于 条目 b 的 键,则条目 a 小于条目 b。
在上面两个算法中,按降序排序键和作用域的效果是将“foo/bar/
”放在“foo/
”之前。这反过来在模块标识符解析期间使“foo/bar/
”的优先级高于“foo/
”。
要规范化模块完整性映射,给定一个有序映射originalMap
令normalized 为一个空的有序映射。
对于originalMap的每个key → value
令resolvedURL 为给定key 和baseURL 的解析 URL 样式模块标识符的结果。
与“imports
”不同,完整性映射的键被视为 URL,而不是模块标识符。但是,我们使用解析 URL 样式模块标识符算法来禁止“裸”相对 URL(例如 foo
),这些 URL 可能被误认为是模块标识符。
如果resolvedURL 为空,则
如果value 不是一个字符串,则
将normalized[resolvedURL] 设置为value。
返回normalized。
要规范化标识符键,给定一个字符串specifierKey 和一个URLbaseURL
如果specifierKey 为空字符串,则
用户代理可以向控制台报告警告,表明标识符键不能是空字符串。
返回null。
令url 为给定specifierKey 和baseURL 的解析 URL 样式模块标识符的结果。
如果url 不为空,则返回url 的序列化。
返回specifierKey。
JavaScript 规范包含许多实现定义的抽象操作,这些操作会根据主机环境而有所不同。本节为用户代理主机定义了这些操作。
JavaScript 包含一个实现定义的HostEnsureCanAddPrivateElement(O) 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]
如果O 是一个WindowProxy
对象,或者实现 Location
,则返回 Completion { [[Type]]: throw, [[Value]]: 一个新的 TypeError
}。
返回NormalCompletion(unused)。
JavaScript 私有字段可以应用于任意对象。由于这可能会为特别奇特的宿主对象极大地复杂化实现,因此 JavaScript 语言规范提供了此钩子,允许宿主拒绝符合宿主定义标准的对象上的私有字段。在 HTML 的情况下,WindowProxy
和 Location
具有复杂的语义 - 特别是在导航和安全性方面 - 这使得私有字段语义的实现具有挑战性,因此我们的实现只是拒绝这些对象。
JavaScript 包含一个实现定义的HostEnsureCanCompileStrings 抽象操作,由 动态代码品牌检查 提案重新定义。用户代理必须使用以下实现:[JAVASCRIPT] [JSDYNAMICCODEBRANDCHECKS]
执行 ? EnsureCSPDoesNotBlockStringCompilation(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg)。 [CSP]
动态代码品牌检查 提案包含一个实现定义的HostGetCodeForEval(argument) 抽象操作。用户代理必须使用以下实现:[JSDYNAMICCODEBRANDCHECKS]
如果argument 是一个TrustedScript
对象,则返回argument 的数据。
否则,返回无代码。
JavaScript 包含一个实现定义的HostPromiseRejectionTracker(promise, operation) 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]
令script 为正在运行的脚本。
令settingsObject 为当前设置对象。
如果script 不为空,则将settingsObject 设置为script 的设置对象。
令global 为settingsObject 的全局对象。
如果operation 为“reject
”,则
将promise 追加到global 的即将通知的拒绝承诺列表。
如果operation 为“handle
”,则
如果global 的即将通知的拒绝承诺列表包含promise,则从该列表中删除promise 然后返回。
如果global 的未完成的拒绝承诺弱集 未包含promise,则返回。
从global 的未完成的拒绝承诺弱集 中删除promise。
在DOM 操作任务源 上排队一个全局任务,给定global,以在global 上触发一个名为rejectionhandled
的事件,使用PromiseRejectionEvent
,其中promise
属性初始化为promise,而reason
属性初始化为promise.[[PromiseResult]]。
Temporal 提案包含一个实现定义的HostSystemUTCEpochNanoseconds 抽象操作。用户代理必须使用以下实现:[JSTEMPORAL]
令settingsObject 为global 的相关设置对象。
令time 为settingsObject 的当前墙上时间。
令ns 为从Unix 纪元 到time 的纳秒数,四舍五入到最接近的整数。
返回将ns 钳位到nsMinInstant 和nsMaxInstant 之间的结果。
Reference/Global_Objects/Promise#Incumbent_settings_object_tracking
仅在一个引擎中支持。
JavaScript 规范定义了工作,这些工作由宿主调度和稍后运行,以及 JobCallback 记录,它们封装了作为工作的一部分调用的 JavaScript 函数。JavaScript 规范包含许多 实现定义的 抽象操作,允许宿主定义如何调度工作以及如何处理 JobCallbacks。HTML 使用这些抽象操作来 跟踪 现任设置对象 在 promises 和 FinalizationRegistry
回调中,方法是保存和恢复 现任设置对象 和 JavaScript 执行上下文 用于 活动脚本 在 JobCallbacks 中。本节为用户代理宿主定义它们。
JavaScript 包含一个 实现定义的 HostCallJobCallback(callback, V, argumentsList) 抽象操作,允许宿主在从任务内部调用 JavaScript 回调时恢复状态。用户代理必须使用以下实现:[JAVASCRIPT]
令 现任设置 为 callback.[[HostDefined]].[[IncumbentSettings]]。
令 脚本执行上下文 为 callback.[[HostDefined]].[[ActiveScriptContext]]。
准备运行回调 使用 现任设置。
这会影响 现任 回调运行时的概念。
如果 脚本执行上下文 不是 null,则 将 脚本执行上下文 推入 JavaScript 执行上下文堆栈 中。
这会影响 活动脚本 回调运行时的概念。
令 result 为 Call(callback.[[Callback]], V, argumentsList)。
如果 脚本执行上下文 不是 null,则 弹出 脚本执行上下文 从 JavaScript 执行上下文堆栈 中。
清理运行回调后的操作 使用 现任设置。
返回 result。
JavaScript 能够使用 FinalizationRegistry
对象注册对象,以便在发现它们被垃圾收集时调度清理操作。JavaScript 规范包含一个 实现定义的 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry) 抽象操作来调度清理操作。
清理工作的时机和发生是 实现定义的 在 JavaScript 规范中。用户代理在何时以及是否对对象进行垃圾回收方面可能有所不同,这会影响 WeakRef.prototype.deref()
方法的值是否为 undefined,以及 FinalizationRegistry
清理回调是否发生。在流行的网络浏览器中,有众所周知的案例,这些案例中的对象无法被 JavaScript 访问,但它们会无限期地被垃圾收集器保留。HTML 在 执行微任务检查点 算法中清除保持活动的 WeakRef
对象。作者最好不要依赖垃圾收集实现的时机细节。
清理操作不会在同步 JavaScript 执行中交错进行,而是在排队的 任务 中发生。用户代理必须使用以下实现:[JAVASCRIPT]
令 global 为 finalizationRegistry.[[Realm]] 的 全局对象。
在全局任务队列中排队 在给定的 global 上 JavaScript 引擎任务源 上执行以下步骤
令 entry 为 finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]] 的 环境设置对象。
检查我们是否可以运行脚本 使用 entry。如果这返回“不运行”,则返回。
准备运行脚本 使用 entry。
这会影响 entry 清理回调运行时的概念。
令 result 为执行 CleanupFinalizationRegistry(finalizationRegistry) 的结果。
清理运行脚本后的操作 使用 entry。
JavaScript 包含一个 实现定义的 HostEnqueueGenericJob(job, realm) 抽象操作,在特定领域执行通用工作(例如,解析由 Atomics.waitAsync
生成的 promises)。用户代理必须使用以下实现:[JAVASCRIPT]
令 global 为 realm 的 全局对象。
在全局任务队列中排队 在给定的 global 上 JavaScript 引擎任务源 上执行 job()。
JavaScript 包含一个 实现定义的 HostEnqueuePromiseJob(job, realm) 抽象操作,用于调度与 Promise 相关的操作。HTML 在微任务队列中调度这些操作。用户代理必须使用以下实现:[JAVASCRIPT]
如果 realm 不是 null,则令 job 设置 为 realm 的 设置对象。否则,令 job 设置 为 null。
如果 realm 不是 null,它就是将要运行的作者代码的 领域。当 job 由 NewPromiseReactionJob 返回时,它是 promise 的处理程序函数的领域。当 job 由 NewPromiseResolveThenableJob 返回时,它是 then
函数的领域。
如果 realm 为 null,则要么没有作者代码会运行,要么作者代码保证会抛出异常。对于前者,作者可能没有传递要运行的代码,例如在 promise.then(null, null)
中。对于后者,这是因为传递了撤销的代理。在这两种情况下,所有原本会使用 job 设置 的后续步骤都将跳过。
NewPromiseResolveThenableJob 和 NewPromiseReactionJob 似乎都为撤销的代理提供非 null 领域(当前领域记录)。可以更新以前的文本以反映这一点。
在微任务队列中排队 执行以下步骤
如果 job 设置 不是 null,则 检查我们是否可以运行脚本 使用 job 设置。如果这返回“不运行”,则返回。
如果 job 设置 不是 null,则 准备运行脚本 使用 job 设置。
这会影响 entry 工作运行时的概念。
令 result 为 job()。
job 是由 NewPromiseReactionJob 或 NewPromiseResolveThenableJob 返回的 抽象闭包。当 job 由 NewPromiseReactionJob 返回时,promise 的处理程序函数;而当 job 由 NewPromiseResolveThenableJob 返回时,则为 then
函数。这些函数都包装在 JobCallback 记录 中。HTML 将 当前设置对象 和一个 JavaScript 执行上下文 保存到 HostMakeJobCallback 中的 活动脚本,并在 HostCallJobCallback 中恢复它们。
如果 job 设置 不为 null,则使用 job 设置 进行 运行脚本后的清理。
如果 result 是一个 非正常完成,则针对 realm 的 全局对象,使用 result.[[Value]] 报告异常。
存在一个非常棘手的情况,即 HostEnqueuePromiseJob 被调用时 realm 为 null(例如,因为 Promise.prototype.then 被调用时处理程序为 null),但 job 也会非正常返回(因为 promise 功能的 resolve 或 reject 处理程序抛出了异常,可能是因为这是一个 Promise 的子类,它接受提供的函数并将它们包装在抛出异常的函数中,然后将它们传递给传递给 Promise 超类构造函数的函数。在这种情况下,应该使用哪个全局对象?考虑到当前 realm 在每个步骤都可能不同,例如使用来自另一个 realm 的 Promise 构造函数或 Promise.prototype.then?请参见 问题 #10526。
JavaScript 包含一个 实现定义的 HostEnqueueTimeoutJob(job, milliseconds) 抽象操作,用于在超时后调度一个操作。HTML 使用 在超时后运行步骤 来调度这些操作。用户代理必须使用以下实现:[JAVASCRIPT]
令 global 为 realm 的 全局对象。
令 timeoutStep 为一个算法步骤,该步骤 在全局任务源上排队一个全局任务,该全局任务源由 global 提供,以执行 job()。
使用 global、"JavaScript
"、milliseconds 和 timeoutStep 进行 在超时后运行步骤。
JavaScript 包含一个 实现定义的 HostMakeJobCallback(callable) 抽象操作,用于让主机将状态附加到从 任务 内部调用的 JavaScript 回调。用户代理必须使用以下实现:[JAVASCRIPT]
令 当前设置 为 当前设置对象。
令 活动脚本 为 活动脚本。
令 脚本执行上下文 为 null。
如果 活动脚本 不为 null,则将 脚本执行上下文 设置为一个新的 JavaScript 执行上下文,其 Function 字段设置为 null,其 Realm 字段设置为 活动脚本 的 设置对象 的 realm,其 ScriptOrModule 字段设置为 活动脚本 的 记录。
如下所示,这用于将当前 活动脚本 传播到调用 job 回调的时间。
当 活动脚本 不为 null 时,将它保存起来很有用,例如以下情况:
Promise. resolve( 'import(`./example.mjs`)' ). then( eval);
如果没有此步骤(以及在 HostCallJobCallback 中使用它的步骤),当评估 import()
表达式时,就不会有 活动脚本,因为 eval()
是一个内置函数,它不源于任何特定的 脚本。
如果用户单击以下按钮,则 活动脚本 可能为 null:
< button onclick = "Promise.resolve('import(`./example.mjs`)').then(eval)" > Click me</ button >
在这种情况下,事件处理程序 的 JavaScript 函数将由 获取事件处理程序的当前值 算法创建,该算法创建一个具有 null [[ScriptOrModule]] 值的函数。因此,当 promise 机制调用 HostMakeJobCallback 时,将没有 活动脚本 传递。
因此,这意味着当评估 import()
表达式时,仍然没有 活动脚本。幸运的是,我们的 HostLoadImportedModule 实现通过回退到使用 当前设置对象 的 API 基本 URL 来处理这种情况。
返回 JobCallback 记录 { [[Callback]]: callable, [[HostDefined]]: { [[IncumbentSettings]]: 当前设置, [[ActiveScriptContext]]: 脚本执行上下文 } }。
JavaScript 规范定义了模块的语法,以及它们处理模型中一些与主机无关的部分。本规范定义了它们处理模型的其余部分:模块系统是如何引导的,通过 script
元素(其 type
属性设置为 "module
"),以及模块是如何被获取、解析和执行的。 [JAVASCRIPT]
虽然 JavaScript 规范在 "脚本" 和 "模块" 之间进行区分,但本规范通常使用 传统脚本 和 模块脚本 进行区分,因为它们都使用 script
元素。
modulePromise = import(specifier)
返回对由 specifier 标识的 模块脚本 的模块命名空间对象的 promise。这允许在运行时动态导入模块脚本,而不是使用静态的 import
语句形式。该指定符将相对于 活动脚本 进行 解析。
如果给出了无效的指定符,或者在 获取 或评估生成的模块图时遇到错误,则返回的 promise 将被拒绝。
url = import.meta.url
此语法只能在 模块脚本 中使用。
url = import.meta.resolve(specifier)
返回相对于 活动脚本 进行 解析 的 specifier。也就是说,这将返回通过使用 import(specifier)
导入的 URL。
如果给出了无效的指定符,则抛出 TypeError
异常。
此语法只能在 模块脚本 中使用。
模块映射是一个由映射构成的元组,它由URL 记录和字符串组成。该URL 记录是模块被获取时的请求 URL,而字符串表示模块的类型(例如,“javascript-or-wasm
”)。模块映射的值要么是模块脚本,要么是 null(用于表示获取失败),要么是占位符值“fetching
”。模块映射用于确保导入的模块脚本在每个Document
或worker中只被获取、解析和评估一次。
由于模块映射是按(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" ;
因此,在这个第二个示例中,只会发生一次获取和一次模块评估。
由于模块类型也是模块映射键的一部分,因此以下代码将在模块映射中创建两个单独的条目(第一个的类型是“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 >
Reference/Operators/import.meta/resolve
在所有当前引擎中支持。
Reference/Operators/import.meta
在所有当前引擎中支持。
JavaScript 包含一个实现定义的HostGetImportMetaProperties 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]
令 moduleScript 为 moduleRecord.[[HostDefined]]。
断言:moduleScript 的基本 URL不为 null,因为 moduleScript 是一个JavaScript 模块脚本。
令 steps 为以下步骤,给定参数 specifier
令 resolveFunction 为 ! CreateBuiltinFunction(steps, 1, "resolve
", « »).
返回 « 记录 { [[Key]]: "url
", [[Value]]: urlString }, 记录 { [[Key]]: "resolve
", [[Value]]: resolveFunction } ».
《导入属性》提案包含一个实现定义的HostGetSupportedImportAttributes 抽象操作。用户代理必须使用以下实现:[JSIMPORTATTRIBUTES]
返回 « "type
" »。
JavaScript 包含一个实现定义的HostLoadImportedModule 抽象操作。用户代理必须使用以下实现:[JAVASCRIPT]
令 settingsObject 为当前设置对象。
如果 settingsObject 的全局对象实现了WorkletGlobalScope
或ServiceWorkerGlobalScope
,并且 loadState 未定义,则
loadState 在当前获取过程由动态import()
调用(直接或加载动态导入模块的传递依赖关系时)启动时为未定义。
令 completion 为完成记录 { [[Type]]: throw, [[Value]]: 新的TypeError
,[[Target]]: empty }。
执行FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
返回。
令 referencingScript 为 null。
令 originalFetchOptions 为默认脚本获取选项。
令 fetchReferrer 为 "client
"。
将 referencingScript 设置为 referrer.[[HostDefined]]。
将 settingsObject 设置为 referencingScript 的设置对象。
将 fetchReferrer 设置为 referencingScript 的基本 URL。
将 originalFetchOptions 设置为 referencingScript 的获取选项。
referrer 通常是脚本记录或循环模块记录,但它不会是获取事件处理程序的当前值算法中的事件处理程序。例如,给定
< button onclick = "import('./foo.mjs')" > Click me</ button >
如果click
事件发生,则在import()
表达式运行时,GetActiveScriptOrModule将返回 null,此操作将接收当前领域作为回退 referrer。
如果 referrer 是循环模块记录,并且 moduleRequest 等于 referrer.[[RequestedModules]] 的第一个元素,则
对于模块请求记录 requested 的 referrer.[[RequestedModules]]
如果 moduleRequest.[[Attributes]] 包含一个记录 entry,使得 entry.[[Key]] 不为 "type
",则
令 completion 为完成记录 { [[Type]]: throw, [[Value]]: 新的SyntaxError
异常,[[Target]]: empty }。
执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。
返回。
JavaScript 规范重新执行此验证,但此处重复是为了避免在验证失败时不必要地加载任何依赖项。
根据 referencingScript 和 moduleRequest.[[Specifier]] 解析模块说明符,捕获任何异常。如果它们抛出异常,则将 resolutionError 设置为抛出的异常。
如果上一步抛出异常,则
将 completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }。
执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。
返回。
将 moduleType 设置为根据 moduleRequest 运行 模块类型从模块请求 步骤的结果。
如果根据 moduleType 和 settings 运行 允许的模块类型 步骤的结果为 false,则
将 completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: 新的 TypeError
异常,[[Target]]: empty }。
执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。
返回。
此步骤实质上是在对静态模块依赖项列表进行首次调用 HostLoadImportedModule 时验证所有请求的模块说明符和类型属性,以避免在任何一个依赖项具有静态错误的情况下进一步加载操作。我们将具有无法解析的模块说明符或不受支持的类型属性的模块视为无法解析的模块;在这两种情况下,语法问题都使得以后无法考虑链接该模块。
根据 settingsObject 禁止进一步导入映射。
将 url 设置为根据 referencingScript 和 moduleRequest.[[Specifier]] 解析模块说明符 的结果,捕获任何异常。如果它们抛出异常,则将 resolutionError 设置为抛出的异常。
如果上一步抛出异常,则
将 completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }。
执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。
返回。
将 fetchOptions 设置为根据 originalFetchOptions、url 和 settingsObject 获取后代脚本获取选项 的结果。
将 destination 设置为 "script"
。
将 fetchClient 设置为 settingsObject。
如果 loadState 不为 undefined,则
将 destination 设置为 loadState.[[Destination]]。
将 fetchClient 设置为 loadState.[[FetchClient]]。
根据 url、fetchClient、destination、fetchOptions、settingsObject、fetchReferrer、moduleRequest 和 onSingleFetchComplete(如下定义)获取单个导入的模块脚本。如果 loadState 不为 undefined 且 loadState.[[PerformFetch]] 不为 null,则将 loadState.[[PerformFetch]] 作为参数传递。
给定 moduleScript 的 onSingleFetchComplete 是以下算法
将 completion 设置为 null。
如果 moduleScript 为 null,则将 completion 设置为 完成记录 { [[Type]]: throw, [[Value]]: 新的 TypeError
,[[Target]]: empty }。
否则,如果 moduleScript 的 解析错误 不为 null,则
否则,将 completion 设置为 完成记录 { [[Type]]: normal, [[Value]]: moduleScript 的 记录,[[Target]]: empty }。
执行 FinishLoadingImportedModule(referrer, moduleRequest, payload, completion)。
为了协调事件、用户交互、脚本、渲染、网络等,用户代理必须使用本节所述的 事件循环。每个 代理 都有一个与之关联的 事件循环,该循环是该代理所独有的。
一个 同源窗口代理 的 事件循环 被称为 窗口事件循环。一个 专用工作线程代理、共享工作线程代理 或 服务工作线程代理 的 事件循环 被称为 工作线程事件循环。一个 工作线程代理 的 事件循环 被称为 工作线程事件循环。
事件循环 不一定对应于实现线程。例如,多个 窗口事件循环 可以在一个线程中协同调度。
但是,对于分配了 [[CanBlock]] 设置为 true 的各种工作线程 代理,JavaScript 规范确实对它们在 向前进展 方面的要求,这实际上相当于在这些情况下要求专用每个代理的线程。
一个 事件循环 有一个或多个 任务队列。一个 任务队列 是一个 集合,其中包含 任务。
任务队列 是 集合,而不是 队列,因为 事件循环处理模型 从选定的队列中获取第一个 可运行 的 任务,而不是 出队 第一个任务。
任务封装了负责以下工作的算法
在特定 EventTarget
对象上分派 Event
对象通常由一个专用的任务完成。
并非所有事件都使用 任务队列 分派;许多事件是在其他任务期间分派的。
HTML 解析器 对一个或多个字节进行标记,然后处理任何生成的标记,这通常是一个任务。
调用回调通常由一个专用的任务完成。
当算法 获取 资源时,如果获取以非阻塞方式发生,则一旦资源的某些部分或全部可用,就会通过任务来处理资源。
某些元素有在 DOM 操作时触发的任务,例如,当该元素 插入到文档中 时。
形式上,一个 任务 是一个 结构,它具有
Document
,或对于不在 窗口事件循环 中的任务,则为 null。如果任务的 文档 为 null 或 完全激活,则该 任务 为 可运行。
根据其 源 字段,每个 任务 都被定义为来自特定 任务源。对于每个 事件循环,每个 任务源 都必须与特定的 任务队列 相关联。
本质上,任务源 用于标准中将逻辑上不同的任务类型分开,而用户代理可能希望在这些任务类型之间进行区分。任务队列 用于用户代理在给定的 事件循环 中合并任务源。
例如,用户代理可以为鼠标和键盘事件创建一个 任务队列(与 用户交互任务源 相关联),另一个用于与所有其他 任务源 相关联。然后,利用 事件循环处理模型 的初始步骤中给予的自由度,它可以四分之三的时间内优先处理键盘和鼠标事件,保持界面响应,但不会使其他任务队列饿死。请注意,在此设置中,处理模型仍然强制要求用户代理绝不会以乱序方式处理来自任何一个 任务源 的事件。
每个 事件循环 都有一个 当前正在运行的任务,它是一个 任务 或 null。最初,它是 null。它用于处理重入。
每个 事件循环 都有一个 微任务队列,它是一个 队列,其中包含 微任务,最初为空。一个 微任务 是指通过 排队一个微任务 算法创建的 任务 的非正式说法。
每个 事件循环 都有一个 执行微任务检查点 布尔值,它最初为 false。它用于防止 执行微任务检查点 算法的重入调用。
每个 窗口事件循环 都有一个 DOMHighResTimeStamp
上次渲染机会时间,最初设置为零。
每个 窗口事件循环 都有一个 DOMHighResTimeStamp
上次空闲时段开始时间,最初设置为零。
要获取 窗口事件循环 loop 的 同循环窗口,返回所有 Window
对象,这些对象的 相关代理 的 事件循环 为 loop。
要对 任务源 source 排队一个任务,它执行一系列步骤 steps,可选地给出事件循环 event loop 和文档 document
如果未给出 event loop,则将 event loop 设置为 隐式事件循环。
如果未给出 document,则将 document 设置为 隐式文档。
令 task 为一个新的 任务。
将 task 的 步骤 设置为 steps。
将 task 的 源 设置为 source。
将 task 的 文档 设置为 document。
将 task 的 脚本评估环境设置对象集 设置为空的 集。
令 queue 为 任务队列,source 在 event loop 上与它相关联。
追加 task 到 queue。
未能传递事件循环和文档到 排队一个任务 意味着依赖模棱两可且定义不明确的 隐式事件循环 和 隐式文档 概念。规范作者应该始终传递这些值,或者使用包装算法 排队一个全局任务 或 排队一个元素任务。建议使用包装算法。
要对 任务源 source 排队一个全局任务,具有一个 全局对象 global 和一系列步骤 steps
令 document 为 global 的 关联的 Document
,如果 global 是一个 Window
对象;否则为 null。
排队一个任务,给出 source、event loop、document 和 steps。
要对 任务源 source 排队一个元素任务,具有一个元素 element 和一系列步骤 steps
要 排队一个微任务,它执行一系列步骤 steps,可选地给出文档 document
如果未给出 document,则将 document 设置为 隐式文档。
令 microtask 为一个新的 任务。
将 microtask 的 步骤 设置为 steps。
将 microtask 的 源 设置为 微任务任务源。
将 microtask 的 文档 设置为 document。
将 microtask 的 脚本评估环境设置对象集 设置为空的 集。
微任务可能被移动到常规的 任务队列 中,如果,在它最初执行期间,它 旋转事件循环。这是唯一一个咨询微任务的 源、文档 和 脚本评估环境设置对象集 的情况;它们被 执行微任务检查点 算法忽略。
在排队任务时,隐式事件循环 是可以从调用算法的上下文中推断出的循环。这通常是不言而喻的,因为大多数规范算法只涉及单个 代理(因此只有一个 事件循环)。例外情况是涉及或指定跨代理通信的算法(例如,在窗口和工作线程之间);对于这些情况,隐式事件循环 概念不能依赖,规范在 排队一个任务 时必须明确提供一个 事件循环。
在事件循环 event loop 上排队任务时,隐式文档 的确定方式如下
如果 event loop 不是 窗口事件循环,则返回 null。
如果任务是在元素的上下文中排队的,则返回元素的 节点文档。
如果任务是由或为 脚本 排队的,则返回脚本的 设置对象 的 全局对象 的 关联的 Document
。
断言:永远不会到达此步骤,因为前面条件之一为真。 真的吗?
既有 隐式事件循环 也有 隐式文档 定义模糊,而且存在很多远程动作。希望能够消除这些,特别是 隐式文档。参见 问题 #4980。
一个 事件循环 必须不断运行以下步骤,只要它存在
令 oldestTask 和 taskStartTime 为 null。
如果 事件循环 具有一个 任务队列,其中至少有一个 可运行 的 任务,则
令 taskQueue 为这样一个 任务队列,以 实现定义 的方式选择。
请记住,微任务队列 不是 任务队列,因此不会在此步骤中选择它。但是,与 微任务任务源 相关联的 任务队列 可能在此步骤中被选中。在这种情况下,下一步中选定的 任务 最初是一个 微任务,但它作为 旋转事件循环 的一部分被移动了。
将 taskStartTime 设置为 不安全的共享当前时间。
将 oldestTask 设置为 taskQueue 中第一个 可运行 的 任务,并从 taskQueue 中 删除 它。
如果 oldestTask 的 文档 不为 null,则 记录任务开始时间,给出 taskStartTime 和 oldestTask 的 文档。
执行 oldestTask 的 步骤。
令 taskEndTime 为 不安全的共享当前时间。 [HRT]
如果 oldestTask 不为 null,则
如果这是一个 窗口事件循环,并且在这个 事件循环 的 任务队列 中没有 可运行 的 任务,则
将这个 事件循环 的 上次空闲期开始时间 设置为 不安全的共享当前时间。
令 computeDeadline 为以下步骤
对于这个 事件循环 的 相同循环窗口 中的每个 win,执行 开始空闲期算法,为 win 传入以下步骤:返回调用 computeDeadline 的结果, 粗化,传入 win 的 相关设置对象 的 跨域隔离功能。 [REQUESTIDLECALLBACK]
如果这是一个 工作线程事件循环,则
如果这个 事件循环 的 代理 的单个 域 的 全局对象 是一个 支持的 DedicatedWorkerGlobalScope
,并且用户代理认为它将从在此时更新其渲染中获益,则
令 now 为 当前高分辨率时间,传入 DedicatedWorkerGlobalScope
。 [HRT]
运行那个 DedicatedWorkerGlobalScope
的动画帧回调,传入 now 作为时间戳。
更新那个专用工作线程的渲染,以反映当前状态。
如果 事件循环 的 任务队列 中没有 任务,并且 WorkerGlobalScope
对象的 关闭 标志为 true,则销毁 事件循环,中止这些步骤,恢复在 Web 工作线程 部分下方描述的 运行工作线程 步骤。
一个 窗口事件循环 eventLoop 还必须 并行 运行以下步骤,只要它存在
将 eventLoop 的 上次渲染机会时间 设置为 不安全的共享当前时间。
对于每个具有 渲染机会 的 navigable,在 渲染任务源 上 排队一个全局任务,传入 navigable 的 活动窗口 以 更新渲染
这可能会导致对 更新渲染 的冗余调用。但是,这些调用将没有可观察到的效果,因为根据不必要的渲染步骤,将不需要任何渲染。实现可以引入进一步的优化,例如仅在未排队时才排队此任务。但是,请注意,与该任务关联的文档可能在该任务被处理之前变为非活动状态。
令 frameTimestamp 为 eventLoop 的 上次渲染机会时间。
令 docs 为所有 完全活动 的 Document
对象,其 相关代理 的 事件循环 是 eventLoop,以任意顺序排序,但必须满足以下条件
在下面遍历 docs 的步骤中,每个 Document
必须按在列表中找到的顺序进行处理。
过滤不可渲染文档:从 docs 中删除任何 Document
对象 doc,如果以下任何一项为 true
除了检查 并行 步骤中的渲染机会,我们还需要在此检查渲染机会,因为某些共享相同 事件循环 的文档可能不会在同一时间拥有 渲染机会。
不必要的渲染:从 docs 中移除所有满足以下条件的 Document
对象 doc
从 docs 中移除所有用户代理认为出于其他原因最好跳过更新渲染的 Document
对象。
对于 docs 的每个 doc,显示 doc。
对于 docs 的每个 doc,运行调整大小步骤,用于 doc。 [CSSOMVIEW]
对于 docs 的每个 doc,运行滚动步骤,用于 doc。 [CSSOMVIEW]
对于 docs 的每个 doc,评估媒体查询并报告更改,用于 doc。 [CSSOMVIEW]
对于 docs 的每个 doc,更新动画并发送事件,用于 doc,将 相对高分辨率时间(给定 frameTimestamp 和 doc 的 相关全局对象 作为时间戳)传递到 [WEBANIMATIONS]。
对于 docs 的每个 doc,运行全屏步骤,用于 doc。 [FULLSCREEN]
对于 docs 的每个 doc,如果用户代理检测到与 CanvasRenderingContext2D
或 OffscreenCanvasRenderingContext2D
(context) 关联的后备存储已丢失,则它必须为每个这样的 context 运行 上下文丢失步骤
如果 context 是 CanvasRenderingContext2D
,则将 canvas 设置为 context 的 canvas
属性的值;否则,将 canvas 设置为 context 的 关联的 OffscreenCanvas
对象。
将 context 的 上下文丢失 设置为 true。
将渲染上下文重置为其默认状态,给定 context。
将 shouldRestore 设置为 触发名为 contextlost
的事件,该事件在 canvas 上,且 cancelable
属性被初始化为 true 的结果。
如果 shouldRestore 为 false,则中止这些步骤。
尝试通过使用 context 的属性创建后备存储并将它们与 context 关联来恢复 context。如果失败,则中止这些步骤。
将 context 的 上下文丢失 设置为 false。
触发名为 contextrestored
的事件,该事件在 canvas 上。
对于 docs 的每个 doc,运行动画帧回调,用于 doc,将 相对高分辨率时间(给定 frameTimestamp 和 doc 的 相关全局对象 作为时间戳)传递到。
将 unsafeStyleAndLayoutStartTime 设置为 不安全共享当前时间。
对于 docs 的每个 doc
将 resizeObserverDepth 设置为 0。
当为 true 时
重新计算样式并更新 doc 的布局。
将 hadInitialVisibleContentVisibilityDetermination 设置为 false。
对于每个 'auto' 用作 'content-visibility' 的值 的元素 element
如果 hadInitialVisibleContentVisibilityDetermination 为 true,则继续。
此步骤的目的是为了使初始视口距离确定(立即生效)反映在循环之前步骤中执行的样式和布局计算中。除初始距离确定之外的距离确定将在下一个 渲染机会 生效。 [CSSCONTAIN]
在深度 resizeObserverDepth 上 收集活动调整大小观察,用于 doc。
如果 doc 具有活动调整大小观察
将 resizeObserverDepth 设置为 广播活动调整大小观察(给定 doc)的结果。
如果 doc 已跳过调整大小观察,则 传递调整大小循环错误,给定 doc。
对于 docs 的每个 doc,如果 doc 的 聚焦区域 不是 可聚焦区域,则为 doc 的 视口 运行 聚焦步骤,并将 doc 的 相关全局对象 的 导航 API 的 在进行中的导航期间聚焦已更改 设置为 false。
例如,这可能发生是因为元素添加了 渲染。它也可能发生在 input
元素上,当元素被 禁用 时。
这将 通常触发 blur
事件,以及可能触发的 change
事件。
除了这种异步修复之外,如果 文档的聚焦区域 被删除,则还存在一个 同步修复。后者将 *不会* 触发 blur
或 change
事件。
对于 docs 的每个 doc,执行待处理的过渡操作,用于 doc。 [CSSVIEWTRANSITIONS]
对于 docs 的每个 doc,运行更新交集观察步骤,用于 doc,将 相对高分辨率时间(给定 now 和 doc 的 相关全局对象 作为时间戳)传递到。 [INTERSECTIONOBSERVER]
对于 docs 的每个 doc,记录渲染时间,用于 doc,给定 unsafeStyleAndLayoutStartTime。
对于 docs 中的每个 doc,标记绘制时间 针对 doc。
对于 docs 中的每个 doc,更新 doc 及其 节点可导航 的渲染或用户界面,以反映当前状态。
对于 docs 中的每个 doc,处理顶层移除,给定 doc。
如果用户代理当前能够将 可导航 的内容呈现给用户,则 可导航 具有 渲染机会,考虑硬件刷新率限制和用户代理出于性能原因的节流,但即使内容在视窗之外也认为内容可呈现。
可导航 的 渲染机会 根据硬件限制(如显示刷新率)和其他因素(如页面性能或其 活动文档 的 可见性状态 是否为 "visible
")确定。渲染机会通常以规律的间隔发生。
本规范不强制执行任何特定模型来选择渲染机会。例如,如果浏览器试图实现 60Hz 的刷新率,则渲染机会最多每秒 60 次(大约 16.7 毫秒)发生一次。如果浏览器发现 可导航 无法持续这种速率,则它可能会将该 可导航 的速率降低到每秒 30 次渲染机会,而不是偶尔丢帧。同样,如果 可导航 不可見,用户代理可能會決定將該頁面降低到每秒 4 次渲染機會,甚至更少。
当用户代理要 执行微任务检查点 时
对于每个 环境设置对象 settingsObject,其 负责事件循环 是此 事件循环,通知有关拒绝的承诺 给定 settingsObject 的 全局对象。
执行 ClearKeptObjects()。
当 WeakRef.prototype.deref()
返回一个对象时,该对象将保持活动状态,直到下次调用 ClearKeptObjects(),之后它将再次成为垃圾回收的対象。
当 并行 运行的算法要 等待稳定状态 时,用户代理必须 排队一个微任务 来运行以下步骤,然后必须停止执行(算法的执行在微任务运行时恢复,如以下步骤所述)
运行算法的 同步部分。
如果合适,恢复算法的 并行 执行,如算法步骤中所述。
同步部分 中的步骤用 ⌛ 标记。
要求 旋转事件循环 直到满足条件 goal 的算法步骤等同于替换以下算法步骤
task 可以是 微任务。
将 task source 设置为 task 的 源。
将 old stack 设置为 JavaScript 执行上下文栈 的副本。
并行:
等待直到满足条件 goal。
排队一个任务 到 task source 上,以
将 JavaScript 执行上下文栈 替换为 old stack。
执行原始算法中此 旋转事件循环 实例之后的任何步骤。
这将恢复 task。
停止 task,允许调用它的任何算法恢复。
与本规范和其他规范中的其他算法不同,这些算法的行为类似于编程语言函数调用,旋转事件循环 更像是宏,它通过扩展为一系列步骤和操作,在使用位置节省了打字和缩进。
步骤为以下的算法
执行某事。
旋转事件循环 直到发生很棒的事情。
执行其他事情。
是简写,在“宏扩展”之后,将变为
执行某事。
将 old stack 设置为 JavaScript 执行上下文栈 的副本。
并行:
等待直到发生很棒的事情。
排队一个任务 到执行“执行某事”的任务源上,以
将 JavaScript 执行上下文栈 替换为 old stack。
执行其他事情。
这是一个更完整的替换示例,其中事件循环从并行工作中排队的任务内部旋转。使用 旋转事件循环 的版本
完全展开的版本
并行:
执行并行操作 1。
将 old stack 设置为 null。
执行任务操作 1。
将 old stack 设置为 JavaScript 执行上下文栈 的副本。
等待直到发生很棒的事情。
将 JavaScript 执行上下文栈 替换为 old stack。
执行任务操作 2。
执行并行操作 2。
由于历史原因,本规范中的一些算法要求用户代理在运行 任务 时 暂停,直到满足条件 goal。这意味着运行以下步骤
将 global 设置为 当前全局对象。
将 timeBeforePause 设置为给定 global 的 当前高分辨率时间。
等待直到满足条件 goal。当用户代理具有暂停的 任务 时,相应的 事件循环 不得运行更多 任务,当前正在运行的 任务 中的任何脚本必须阻塞。但是,用户代理在暂停时应该对用户输入保持响应,尽管能力降低,因为 事件循环 不会执行任何操作。
暂停 对用户体验非常不利,尤其是在多个文档共享单个 事件循环 的场景中。鼓励用户代理尝试 暂停 的替代方案,例如 循环事件循环 甚至只是简单地继续执行,而根本不进行任何暂停,只要在保持与现有内容兼容的情况下可以这样做。如果发现一种不太激进的替代方案能够与 Web 兼容,本规范将很乐意进行更改。
在此期间,实现者应注意,用户代理可能尝试使用的各种替代方案可能会改变 事件循环 行为的细微方面,包括 任务 和 微任务 的计时。即使这样做会导致它们违反 暂停 操作隐含的精确语义,实现也应继续尝试。
以下 任务源 用于本规范和其他规范中许多基本无关的功能。
此 任务源 用于对用户交互做出反应的功能,例如键盘或鼠标输入。
对用户输入的响应发送的事件(例如 click
事件)必须使用 任务 排队,任务源为 用户交互任务源。 [UIEVENTS]
此 任务源 用于对网络活动做出反应的功能。
编写与 事件循环 正确交互的规范可能很棘手。这加剧了本规范如何使用与并发模型无关的术语,因此我们说诸如 "事件循环" 和 "并行" 之类的词语,而不是使用更熟悉的特定于模型的术语,例如 "主线程" 或 "在后台线程上"。
默认情况下,规范文本通常在 事件循环 上运行。这来自正式的 事件循环处理模型,因为您最终可以将大多数算法追溯到 任务 排队 到那里。
任何 JavaScript 方法的算法步骤将由调用该方法的作者代码调用。作者代码只能通过排队的任务运行,通常起源于 script
处理模型 中的某个地方。
从这个起点开始,首要准则是,规范需要执行的任何会阻塞 事件循环 的工作必须与它 并行 执行。这包括(但不限于)
执行繁重的计算;
显示面向用户的提示;
执行可能需要涉及外部系统(即 "进程外")的操作。
下一个复杂之处是,在 并行 的算法部分中,您不得创建或操作与特定 领域、全局 或 环境设置对象 关联的对象。(用更熟悉的术语来说,您不得直接从后台线程访问主线程工件。)这样做会导致 JavaScript 代码可观察到的数据竞争,毕竟,您的算法步骤正在并行 于 JavaScript 代码运行。
但是,您可以操作来自 Infra 的规范级数据结构和值,因为它们与领域无关。它们从未直接暴露给 JavaScript,除非进行特定的转换(通常 通过 Web IDL)。 [INFRA] [WEBIDL]
因此,要影响可观察的 JavaScript 对象的世界,您必须 排队一个全局任务 来执行任何此类操作。这确保您的步骤与 事件循环 上发生的其它事情正确交织在一起。此外,您必须在 排队全局任务 时选择一个 任务源;这控制着您的步骤与其它步骤的相对顺序。如果您不确定要使用哪个 任务源,请选择最适合的 通用任务源 之一。最后,您必须指出排队的任务与哪个 全局对象 相关联;这确保如果该全局对象处于非活动状态,则任务不会运行。
排队全局任务 的基础原语是 排队任务 算法。通常,排队全局任务 更好,因为它会自动选择正确的 事件循环,并在适当的情况下,选择 文档。较旧的规范通常使用 排队任务 以及 隐式事件循环 和 隐式文档 概念,但这不鼓励这样做。
将所有这些放在一起,我们可以提供一个模板,用于典型需要异步执行工作的算法
执行任何同步设置工作,同时仍在 事件循环 上。这可能包括将 领域 特定的 JavaScript 值转换为与领域无关的规范级值。
并行 执行一组可能很昂贵的步骤,完全在与领域无关的值上进行操作,并生成与领域无关的结果。
排队一个全局任务,在指定的 任务源 上,并给定适当的 全局对象,将与领域无关的结果转换回 事件循环 上 JavaScript 对象的可观察世界上的可观察影响。
以下是一个算法,它在解析为 URL 后,对传入的 列表 input 中的 标量值字符串 进行 "加密"。
令 urls 为一个空的 列表。
对 input 的每个 string
如果 parsed 失败,则返回 一个使用 "SyntaxError
" DOMException
拒绝的承诺。
令 serialized 为将 URL 序列化器 应用于 parsed 生成的结果。
令 realm 为 当前领域。
令 p 为一个新的承诺。
并行 运行以下步骤
返回 p。
以下是关于此算法的几个需要注意的地方
它在事件循环上提前进行 URL 解析,然后再进行并行步骤。这是必要的,因为解析依赖于当前设置对象,而该对象在进行并行步骤后将不再是当前设置对象。
或者,它可以保存对当前设置对象的API 基地址的引用,并在并行步骤中使用它;这将是等效的。但是,我们建议尽可能提前完成工作,就像此示例一样。尝试保存正确的值可能会导致错误;例如,如果我们保存了当前设置对象而不是它的API 基地址,那么就会存在潜在的竞争条件。
Promise 作为可观察的 JavaScript 对象,永远不会在并行步骤中创建和操作。p是在进入这些步骤之前创建的,然后在任务中进行操作,该任务专门为此目的而被排队。
JavaScript 数组对象的创建也发生在排队的任务中,并且小心地指定了在哪个领域中创建数组,因为这不再从上下文中显而易见。
(关于最后两点,还可以参考whatwg/webidl 问题 #135 和whatwg/webidl 问题 #371,我们仍在考虑上述 Promise 解析模式的细微差别。)
需要注意的另一件事是,如果该算法是从 Web IDL 指定的操作(接受 sequence
<USVString
>)中调用的,则会自动将作者作为输入提供的领域特定的 JavaScript 对象转换为领域无关的 sequence
<USVString
> Web IDL 类型,然后我们将它视为列表,其中包含标量值字符串。因此,根据规范的结构方式,主事件循环上可能还有其他隐式步骤,这些步骤参与了准备并行运行的整个过程。
许多对象可以指定事件处理程序。这些充当指定它们的 对象上的非捕获事件监听器。[DOM]
一个值,它可以是 null、回调对象或内部原始未编译的处理程序。
回调函数类型描述了它是如何暴露给脚本的。最初,事件处理程序的值必须设置为 null。EventHandler
一个监听器,它可以是 null 或事件监听器,负责运行事件处理程序处理算法。最初,事件处理程序的监听器必须设置为 null。
事件处理程序通过两种方式暴露。
第一种方式,对所有事件处理程序都适用,是作为事件处理程序 IDL 属性。
第二种方式是作为事件处理程序内容属性。HTML 元素上的事件处理程序以及一些Window
对象上的事件处理程序通过这种方式暴露。
对于这两种方式,事件处理程序都是通过名称暴露的,该名称是一个字符串,始终以“on
”开头,后面跟着处理程序打算处理的事件的名称。
大多数情况下,暴露事件处理程序的对象与添加相应事件监听器的对象相同。但是,
和 body
元素会暴露几个事件处理程序,这些处理程序会作用于元素的frameset
对象(如果存在)。在任何情况下,我们都将该对象称为事件处理程序作用于的目标。Window
要确定事件处理程序的目标,给定一个EventTarget
对象eventTarget,该对象暴露了事件处理程序,以及一个事件处理程序名称name,将执行以下步骤
如果name不是WindowEventHandlers
接口混合的属性成员的名称,并且Window
反射的 body 元素事件处理程序集不包含name,则返回eventTarget。
如果eventTarget的节点文档不是活动文档,则返回 null。
这可能会发生在该对象是
元素,但没有对应的body
对象时,例如。Window
此检查不一定会阻止
和 body
元素(这些元素不是其节点文档的body 元素)到达下一步。特别是,在活动文档中创建的frameset
元素(可能使用body
)但未连接,其对应的document.createElement()
对象也将作为通过该元素暴露的几个事件处理程序的目标。Window
每个指定了一个或多个事件处理程序的EventTarget
对象都与一个关联的事件处理程序映射相关联,该映射是一个映射,用于将表示名称的字符串映射到事件处理程序。
当创建一个指定了一个或多个事件处理程序的EventTarget
对象时,其事件处理程序映射必须初始化,使其包含每个事件处理程序的条目,这些事件处理程序将该对象作为目标,并且这些事件处理程序中的项设置为其初始值。
条目在事件处理程序映射中创建的顺序可能是任意的。它不会通过对映射进行操作的任何算法进行观察。
不会在对象的事件处理程序映射中为那些仅仅在该对象上暴露但将其他对象作为其目标的事件处理程序创建条目。
一个事件处理程序 IDL 属性 是一个 IDL 属性,用于特定的事件处理程序。IDL 属性的名称与名称相同,该事件处理程序。
当调用事件处理程序 IDL 属性的 getter 时,必须运行以下步骤,其中 name 为名称。
令 eventTarget 为确定事件处理程序的目标的结果,该结果基于此对象和 name。
如果 eventTarget 为 null,则返回 null。
返回获取事件处理程序的当前值的结果,该结果基于 eventTarget 和 name。
当调用事件处理程序 IDL 属性的 setter 时,必须运行以下步骤,其中 name 为名称。
令 eventTarget 为确定事件处理程序的目标的结果,该结果基于此对象和 name。
如果 eventTarget 为 null,则返回。
如果给定值为 null,则停用事件处理程序,该结果基于 eventTarget 和 name。
否则
某些事件处理程序 IDL 属性有额外的要求,特别是onmessage
属性,该属性属于 MessagePort
对象。
一个事件处理程序内容属性 是一个内容属性,用于特定的事件处理程序。内容属性的名称与名称相同,该事件处理程序。
当指定事件处理程序内容属性时,它们必须包含有效的 JavaScript 代码,这些代码在解析后将匹配 FunctionBody 产生式,在自动分号插入后。
以下属性更改步骤用于在事件处理程序内容属性与事件处理程序之间进行同步:[DOM]
如果 namespace 不为 null,或者 localName 不是element 上的事件处理程序内容属性的名称,则返回。
令 eventTarget 为确定事件处理程序的目标的结果,该结果基于 element 和 localName。
如果 eventTarget 为 null,则返回。
如果 value 为 null,则停用事件处理程序,该结果基于 eventTarget 和 localName。
否则
如果元素的内联行为是否应被内容安全策略阻止?算法在element、"script attribute
" 和 value 上执行时返回 "Blocked
",则返回。 [CSP]
令 handlerMap 为 eventTarget 的事件处理程序映射。
令 eventHandler 为 handlerMap[localName]。
令 location 为触发执行这些步骤的脚本位置。
将 eventHandler 的值设置为内部原始未编译处理程序 value/location。
激活事件处理程序,该结果基于 eventTarget 和 localName。
根据 DOM 标准,即使 oldValue 和 value 相同(将属性设置为其当前值),这些步骤也会运行,但如果 oldValue 和 value 都为 null(删除当前不存在的属性),则不会运行这些步骤。 [DOM]
为了停用事件处理程序,请提供 EventTarget
对象 eventTarget 和一个字符串 name,该字符串是名称,用于事件处理程序,运行以下步骤。
令 handlerMap 为 eventTarget 的事件处理程序映射。
令 eventHandler 为 handlerMap[name]。
将 eventHandler 的值设置为 null。
令 listener 为 eventHandler 的侦听器。
如果 listener 不为 null,则使用 eventTarget 和 listener删除事件侦听器。
将 eventHandler 的侦听器设置为 null。
为了擦除所有事件侦听器和处理程序,请提供 EventTarget
对象 eventTarget,运行以下步骤。
如果 eventTarget 具有关联的事件处理程序映射,则对于 eventTarget 的关联事件处理程序映射中的每个 name → eventHandler,停用事件处理程序,该结果基于 eventTarget 和 name。
使用 eventTarget删除所有事件侦听器。
此算法用于定义 document.open()
。
为了激活事件处理程序,请提供 EventTarget
对象 eventTarget 和一个字符串 name,该字符串是名称,用于事件处理程序,运行以下步骤。
令 handlerMap 为 eventTarget 的事件处理程序映射。
令 eventHandler 为 handlerMap[name]。
如果 eventHandler 的侦听器不为 null,则返回。
令 callback 为创建 Web IDL EventListener
实例的结果,该实例代表对一个参数的函数的引用,该函数执行事件处理程序处理算法的步骤,该算法基于 eventTarget、name 和其参数。
EventListener
的回调上下文可以是任意的;它不会影响事件处理程序处理算法的步骤。 [DOM]
回调明确不是事件处理程序本身。每个事件处理程序最终都会注册相同的回调,即下面定义的算法,该算法负责调用正确的代码,并处理代码的返回值。
令 listener 为一个新的事件侦听器,其类型是与 eventHandler 对应的事件处理程序事件类型,其回调是 callback。
为了清楚起见,事件侦听器不同于 EventListener
。
使用 eventTarget 和 listener添加事件侦听器。
将 eventHandler 的侦听器设置为 listener。
事件侦听器注册仅在事件处理程序的值被设置为非 null,并且事件处理程序尚未激活时才会发生。由于侦听器按注册顺序调用,假设没有发生停用,则特定事件类型的事件侦听器的顺序将始终为
在事件处理程序的值第一次被设置为非 null 之前使用 addEventListener()
注册的事件侦听器
然后是当前设置的回调(如果有)
最后是事件处理程序的值第一次被设置为非 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,如下所示。
令 callback 为获取事件处理程序的当前值的结果,该结果基于 eventTarget 和 name。
如果 callback 为 null,则返回。
如果 event 是一个 ErrorEvent
对象,event 的 type
是 "error
",并且 event 的 currentTarget
实现了 WindowOrWorkerGlobalScope
混合,则将 special error event handling 设置为 true。否则,将 special error event handling 设置为 false。
按照以下步骤处理 Event
对象 event。
将 return value 设置为使用「event 的 message
、event 的 filename
、event 的 lineno
、event 的 colno
、event 的 error
」、"rethrow
" 以及 callback this value 设置为 event 的 currentTarget
调用 callback 的结果。
将 return value 设置为使用「event」、"rethrow
" 以及 callback this value 设置为 event 的 currentTarget
调用 callback 的结果。
如果回调函数抛出异常,则重新抛出异常,并结束这些步骤。该异常将传播到 DOM 事件分发逻辑,然后 报告 该异常。
按照以下步骤处理 return value。
BeforeUnloadEvent
对象,并且 event 的 type
是 "beforeunload
"在这种情况下,事件处理程序 IDL 属性 的类型将为 OnBeforeUnloadEventHandler
,因此 return value 将被强制转换为 null 或 DOMString
。
如果 return value 不为 null,则
设置 event 的 canceled flag。
如果 event 的 returnValue
属性的值为空字符串,则将 event 的 returnValue
属性的值设置为 return value。
如果 return value 为 true,则设置 event 的 canceled flag。
如果 return value 为 false,则设置 event 的 canceled flag。
如果我们因为 event 的 type
是 "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
处理程序,返回 true 会取消该事件。
onbeforeunload
处理程序,返回任何非 null 且非 undefined 的值都会取消该事件。
由于历史原因,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,该字符串是 事件处理程序 的 名称,它必须运行以下步骤:
将 handlerMap 设置为 eventTarget 的 事件处理程序映射。
令 eventHandler 为 handlerMap[name]。
如果 eventHandler 的 值 是一个 内部原始未编译处理程序,则
如果 eventTarget 是一个元素,则将 element 设置为 eventTarget,并将 document 设置为 element 的 节点文档。否则,eventTarget 是一个 Window
对象,将 element 设置为 null,并将 document 设置为 eventTarget 的 关联的 Document
。
如果 脚本被禁用,则对于 document 返回 null。
将 body 设置为 eventHandler 的 值 中的未编译脚本主体。
将 location 设置为脚本主体来源的位置,如 eventHandler 的 值 中所示。
如果 element 不为 null 并且 element 有 表单所有者,则将 form owner 设置为该 表单所有者。否则,将 form owner 设置为 null。
将 settings object 设置为 document 的 相关设置对象。
如果 body 无法解析为 FunctionBody 或解析检测到 早期错误,则执行以下子步骤:
将 settings object 的 域执行上下文 推入 JavaScript 执行上下文堆栈;它现在是 正在运行的 JavaScript 执行上下文。
这是必要的,以便后续调用 OrdinaryFunctionCreate 发生在正确的 域 中。
将 function 设置为调用 OrdinaryFunctionCreate 的结果,其参数如下:
将 realm 设置为 settings object 的 域。
将 scope 设置为 realm.[[GlobalEnv]]。
如果 eventHandler 是一个元素的 事件处理程序,则将 scope 设置为 NewObjectEnvironment(document,true,scope)。
如果 form owner 不为空,则将 scope 设置为 NewObjectEnvironment(form owner, true, scope)。
如果 element 不为空,则将 scope 设置为 NewObjectEnvironment(element, true, scope)。
返回 scope。
从 JavaScript 执行上下文栈 中移除 settings object 的 领域执行上下文。
将 function.[[ScriptOrModule]] 设置为 null。
这样做是因为默认行为(将创建的函数与栈上最近的 脚本 关联)会导致路径依赖的结果。例如,一个首先由用户交互调用的事件处理程序最终将具有 null [[ScriptOrModule]](因为此时当 活动脚本 为 null 时,将首先调用此算法),而一个首先由从脚本分派事件调用的事件处理程序将具有其 [[ScriptOrModule]] 设置为该脚本。
相反,我们只将 [[ScriptOrModule]] 始终设置为 null。这无论如何都更直观;将第一个分派事件的脚本与事件处理程序代码相关联的想法是可疑的。
实际上,这只会影响通过 import()
解析相对 URL,后者会查询相关脚本的 基本 URL。将 [[ScriptOrModule]] 设置为 null 意味着 HostLoadImportedModule 将回退到 当前设置对象 的 API 基本 URL。
将 eventHandler 的 值 设置为创建 Web IDL EventHandler
回调函数对象的返回值,该函数对象的引用是 function,并且其 回调上下文 是 settings object。
返回 eventHandler 的 值。
Document
对象和 Window
对象以下是所有 HTML 元素 必须支持的 事件处理程序(以及它们相应的 事件处理程序事件类型),既作为 事件处理程序内容属性 又作为 事件处理程序 IDL 属性;以及所有 Document
和 Window
对象必须支持的事件处理程序,作为 事件处理程序 IDL 属性
事件处理程序 | 事件处理程序事件类型 |
---|---|
onabort 在所有当前引擎中支持。 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 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox10+Safari7+Chrome30+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer5.5+ Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android? | mouseenter
|
onmouseleave 在所有当前引擎中支持。 Firefox10+Safari7+Chrome30+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer5.5+ Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android? | mouseleave
|
onmousemove 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox6+Safari4+Chrome2+ Opera9.5+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android10.1+ | mouseover
|
onmouseup 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox22+Safari3+Chrome1+ Opera12.1+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS3+Chrome Android?WebView Android37+三星浏览器?Opera Android12.1+ | paste
|
onpause 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 Firefox109+Safari不支持Chrome114+ Opera?Edge114+ Edge (Legacy)?Internet ExplorerNo Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android? 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox17+Safari7+Chrome31+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS不支持Chrome Android?WebView Android?三星浏览器?Opera Android? | wheel
|
以下是所有 事件处理程序(及其对应的 事件处理程序事件类型),必须由所有 HTML 元素(除了 body
和 frameset
元素,因为这两个元素既有 事件处理程序内容属性,又有 事件处理程序 IDL 属性)支持;必须由所有 Document
对象支持,作为 事件处理程序 IDL 属性;并且必须由所有 Window
对象支持,作为 事件处理程序 IDL 属性,在 Window
对象本身,以及通过对应的 事件处理程序内容属性 和 事件处理程序 IDL 属性,暴露在由该 Window
对象的 关联 Document
所拥有的所有 body
和 frameset
元素上
事件处理程序 | 事件处理程序事件类型 |
---|---|
onblur 在所有当前引擎中支持。 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+ 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox6+Safari5.1+Chrome10+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android37+三星浏览器?Opera Android? | error
|
onfocus 在所有当前引擎中支持。 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+ 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox6+Safari2+Chrome1+ Opera11.6+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ 在所有当前引擎中支持。 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
所拥有的所有 body
和 frameset
元素上
事件处理程序 | 事件处理程序事件类型 |
---|---|
onafterprint 在所有当前引擎中支持。 Firefox6+Safari13+Chrome63+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android? | afterprint
|
onbeforeprint 在所有当前引擎中支持。 Firefox6+Safari13+Chrome63+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android? | beforeprint
|
onbeforeunload 在所有当前引擎中支持。 Firefox1+Safari3+Chrome1+ Opera12+Edge79+ Edge (旧版)12+Internet Explorer4+ Firefox Android?Safari iOS1+Chrome Android?WebView Android?三星浏览器?Opera Android12+ | beforeunload
|
onhashchange 在所有当前引擎中支持。 Firefox3.6+Safari5+Chrome8+ Opera10.6+Edge79+ Edge (Legacy)12+Internet Explorer8+ Firefox Android?Safari iOS5+Chrome Android?WebView Android37+三星浏览器?Opera Android11+ | hashchange
|
onlanguagechange 在所有当前引擎中支持。 Firefox32+Safari10.1+Chrome37+ Opera?Edge79+ Edge (Legacy)?Internet ExplorerNo Firefox Android4+Safari iOS?Chrome Android?WebView Android?三星浏览器4.0+Opera Android? | languagechange
|
onmessage 在所有当前引擎中支持。 Firefox9+Safari4+Chrome60+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer8+ Firefox Android?Safari iOS4+Chrome Android?WebView Android?Samsung Internet?Opera Android47+ | 消息
|
onmessageerror 在所有当前引擎中支持。 Firefox6+Safari3.1+Chrome3+ Opera11.6+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS3+Chrome Android?WebView Android?Samsung Internet?Opera Android12+ 在所有当前引擎中支持。 Firefox57+Safari16.4+Chrome60+ Opera?Edge79+ Edge (Legacy)18Internet Explorer不支持 Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android47+ | messageerror
|
onoffline 在所有当前引擎中支持。 Firefox9+Safari4+Chrome3+ Opera?Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS3+Chrome Android?WebView Android37+Samsung Internet?Opera Android? | 离线
|
ononline 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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 在所有当前引擎中支持。 Firefox69+Safari11+Chrome49+ Opera?Edge79+ Edge (Legacy)?Internet ExplorerNo Firefox Android?Safari iOS11.3+Chrome Android?WebView Android?Samsung Internet?Opera Android? | rejectionhandled
|
onstorage 在所有当前引擎中支持。 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 在所有当前引擎中支持。 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
|
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 ;
};
某些操作和方法被定义为在元素上触发事件。例如,click()
方法在 HTMLElement
接口上被定义为在元素上触发一个 click
事件。 [UIEVENTS]
在 target 上触发一个名为 e 的合成指针事件,并带有可选的 不可信标志,意味着运行以下步骤
令 event 为使用 PointerEvent
创建事件 的结果。
将 event 的 type
属性初始化为 e。
将 event 的 bubbles
和 cancelable
属性初始化为 true。
设置 event 的 composed 标志。
如果设置了 不可信标志,则将 event 的 isTrusted
属性初始化为 false。
根据当前密钥输入设备的状态(如果有)初始化 event 的 ctrlKey
、shiftKey
、altKey
和 metaKey
属性(对于任何不可用的密钥则为 false)。
将 event 的 view
属性初始化为 target 的 节点文档 的 Window
对象(如果有),否则为 null。
event 的 getModifierState()
方法应返回适当的值来描述当前密钥输入设备的状态。
返回在 target 上 分派 event 的结果。
触发 click
事件 在 target 上意味着 在 target 上触发一个名为 click
的合成指针事件。
WindowOrWorkerGlobalScope
混合WindowOrWorkerGlobalScope
混合用于在 Window
和 WorkerGlobalScope
对象上公开 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
在所有当前引擎中支持。
返回此全局对象是否表示一个 安全上下文。 [SECURE-CONTEXTS]
self.origin
在所有当前引擎中支持。
返回全局对象的 来源,序列化为字符串。
self.crossOriginIsolated
在所有当前引擎中支持。
返回在此全局中运行的脚本是否允许使用需要跨源隔离的 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 的 相关设置对象 的 跨源隔离能力。
atob()
和 btoa()
方法允许开发人员将内容转换为 Base64 编码,反之亦然。
在这些 API 中,出于助记符目的,"b" 可以被视为代表 "binary"(二进制),而 "a" 代表 "ASCII"。然而实际上,主要出于历史原因,这些函数的输入和输出都是 Unicode 字符串。
result = self.btoa(data)
在所有当前引擎中支持。
接收输入数据,该数据为 Unicode 字符串,仅包含 U+0000 到 U+00FF 范围内的字符,每个字符分别代表一个值为 0x00 到 0xFF 的二进制字节,并将其转换为 base64 表示形式,然后返回结果。
如果输入字符串包含任何超出范围的字符,则抛出 "InvalidCharacterError
" DOMException
异常。
result = self.atob(data)
在所有当前引擎中支持。
接收输入数据,该数据为 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)
方法的步骤如下
令 decodedData 为对 data 运行 宽容的 base64 解码 的结果。
如果 decodedData 为失败,则抛出 "InvalidCharacterError
" DOMException
。
返回 decodedData。