DOM

现行标准 — 最后更新

参与:
GitHub whatwg/dom (新问题, 开放的问题)
在 Matrix 上聊天
提交:
GitHub whatwg/dom/commits
此提交的快照
@thedomstandard
测试:
web-platform-tests dom/ (进行中的工作)
翻译 (非规范性)
日本語
简体中文
한국어

摘要

DOM 定义了一个平台中立的模型,用于事件、活动中止和节点树。

1. 基础设施

本规范依赖于现行标准的基础设施标准。[INFRA]

本规范中使用的一些术语在编码选择器受信任类型Web IDLXMLXML中的命名空间中有定义。 [ENCODING] [SELECTORS4] [TRUSTED-TYPES] [WEBIDL] [XML] [XML-NAMES]

当需要扩展时,可以相应地更新 DOM 标准,或者可以编写一个新标准,该标准可以利用为 适用的规范 提供的可扩展性钩子。

1.1.

是一个有限的层次树结构。树的顺序是对的先序、深度优先遍历。

参与的对象有一个父节点,它要么是 null,要么是一个对象,并且有子节点,它是一个对象的有序集合。对象A父节点是对象B,则AB子节点

对象的是它自己,如果它的为null,否则它的根是它的的根。的根是参与该的任意对象,而该对象的为null。

如果对象A是对象B,或者对象A是对象C,而CB后代,则对象A被称为对象B后代

包含后代是指一个对象或其后代之一。

当且仅当BA后代时,称对象A为对象B祖先

包含祖先是指一个对象或其祖先之一。

当且仅当BA共享相同的非空父节点时,称对象A为对象B同胞

包含同胞是指一个对象或其同胞之一。

如果AB在同一个中,并且A树的顺序中位于B之前,则称对象A先于对象B

如果AB在同一个中,并且A树的顺序中位于B之后,则称对象A继于对象B

一个对象的第一个子节点是其第一个子节点,如果它没有子节点,则为 null。

一个对象的最后一个子节点是其最后一个子节点,如果它没有子节点,则为 null。

一个对象的前一个同胞是指其第一个先于同胞,如果没有,则为 null。

一个对象的下一个同胞是指其第一个继于同胞,如果没有,则为 null。

一个对象的索引是其先于同胞的数量,如果没有,则为 0。

1.2. 有序集合

有序集合解析器接受一个字符串input,然后执行以下步骤:

  1. inputTokens在 ASCII 空白字符处分割input的结果。

  2. tokens为一个新的有序集合

  3. 对于 inputTokens 中的每个 token: 将 token 追加tokens

  4. 返回tokens

有序集合序列化器接受一个set,并返回使用U+0020 SPACE连接的set串联结果

1.3. 选择器

给定字符串 selectors节点 node作用域匹配选择器字符串 的步骤如下:

  1. selector解析选择器 selectors 的结果。 [SELECTORS4]

  2. 如果 selector 返回失败,则 抛出一个 "SyntaxError"DOMException

  3. 返回 selectornode根节点 通过 作用域根 node 进行 在树中匹配选择器 的结果。[SELECTORS4]

不打算支持在选择器中使用命名空间,也不会添加此功能。

1.4. 名称验证

当一个字符串满足以下条件时,称为有效的命名空间前缀:其长度至少为1,并且不包含ASCII 空白符、U+0000 NULL、U+002F (/) 或 U+003E (>)。

当一个字符串满足以下条件时,称为有效的属性本地名:其长度至少为1,并且不包含ASCII 空白符、U+0000 NULL、U+002F (/)、U+003D (=) 或 U+003E (>)。

当一个字符串name满足下列步骤返回 true 时,称为有效的元素本地名

  1. 如果name长度为0,则返回 false。

  2. 如果name的第0个码点ASCII 字母

    1. 如果name包含ASCII 空白符、U+0000 NULL、U+002F (/) 或 U+003E (>),则返回 false。

    2. 返回 true。

  3. 如果name的第0个码点不是 U+003A (:)、U+005F (_),也不在 U+0080~U+10FFFF 范围内,则返回 false。

  4. 如果name的后续码点(如有)不是ASCII 字母ASCII 数字、U+002D (-)、U+002E (.)、U+003A (:)、U+005F (_),或者不在 U+0080~U+10FFFF 范围内,则返回 false。

  5. 返回 true。

此概念用于在通过 DOM API 构建时验证元素本地名称。其意图是允许任何可以使用 HTML 解析器构造的名称(第一个码点ASCII 字母的分支),以及一些额外的可能性。对于那些额外的可能性,出于历史原因,ASCII 范围受到限制,但超出 ASCII 的任何内容都是允许的。

以下与 JavaScript 兼容的正则表达式是有效元素本地名称的实现:

/^(?:[A-Za-z][^\0\t\n\f\r\u0020/>]*|[:_\u0080-\u{10FFFF}][A-Za-z0-9-.:_\u0080-\u{10FFFF}]*)$/u
        

一个字符串,如果它不包含ASCII 空白字符、 U+0000 NULL 或 U+003E (>),则它是一个有效的文档类型名称

空字符串是一个有效的文档类型名称

验证并提取一个 namespacequalifiedName,给定一个 context

  1. 如果 namespace 是空字符串,则将其设置为 null。

  2. prefix 设置为 null。

  3. localName 设置为 qualifiedName

  4. 如果 qualifiedName 包含 U+003A (:):

    1. splitResult 设置为运行 严格拆分的结果,参数为 qualifiedName 和 U+003A (:)。

    2. prefix 设置为 splitResult[0]。

    3. localName 设置为 splitResult[1]。

    4. 如果 prefix 不是一个 有效的命名空间前缀,则 抛出一个 "InvalidCharacterError" DOMException

  5. 断言prefix 要么为 null,要么是一个 有效的命名空间前缀

  6. 如果 context 是 "attribute" 并且 localName 不是 有效的属性本地名称,则 抛出一个 "InvalidCharacterError" DOMException

  7. 如果 context 是 "element" 并且 localName 不是 有效的元素本地名称,则 抛出一个 "InvalidCharacterError" DOMException

  8. 如果 prefix 不为 null 且 namespace 为 null,则 抛出一个 "NamespaceError" DOMException

  9. 如果 prefix 是 "xml" 且 namespace 不是 XML 命名空间,则 抛出一个 "NamespaceError" DOMException

  10. 如果 qualifiedNameprefix 是 "xmlns" 并且 namespace 不是 XMLNS 命名空间,则 抛出一个 "NamespaceError" DOMException

  11. 如果 namespaceXMLNS 命名空间 并且 qualifiedNameprefix 均不是 "xmlns",则 抛出一个 "NamespaceError" DOMException

  12. 返回 (namespace, prefix, localName)。

本规范中的各种 API 过去对命名空间前缀、属性本地名称、元素本地名称和文档类型名称的验证更为严格。这样做的方式与各种 XML 相关规范保持一致。(尽管并非所有这些规范中的规则都被强制执行。)

这被发现对 Web 开发人员来说很烦人,特别是因为这意味着有些名称可以通过 HTML 解析器创建,但不能通过 DOM API 创建。因此,验证已放宽到仅限于上述描述的那些。

2. 事件

2.1. “DOM 事件”简介

在整个 Web 平台中,事件派发到对象,以标识发生的事件,例如网络活动或用户交互。这些对象实现了EventTarget接口,因此可以通过调用addEventListener()来添加事件监听器以观察事件

obj.addEventListener("load", imgFetched)

function imgFetched(ev) {
  // great success}

事件监听器可以通过使用removeEventListener()方法删除,传递相同的参数。

或者,也可以通过将AbortSignal传递给addEventListener(),然后调用控制器上持有信号的abort()来删除事件监听器

事件也是对象,并实现了Event接口(或派生接口)。在上面的例子中,ev事件ev作为参数传递给事件监听器回调(通常是如上所示的JavaScript函数)。事件监听器通过事件type属性值(上例中的"load")来区分事件。事件target属性值返回事件派发到的对象(如上例中的obj)。

虽然事件通常由用户代理在用户交互或某些任务完成时派发,但应用程序可以通过使用通常称为合成事件的方式派发事件

// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) })

// create and dispatch the event
var event = new CustomEvent("cat", {"detail":{"hazcheeseburger":true}})
obj.dispatchEvent(event)

除了用于传递信号外,事件有时也用于让应用程序控制操作中的后续步骤。例如,作为表单提交的一部分,type属性值为"submit"的事件派发。如果调用了该事件preventDefault()方法,则表单提交将被终止。希望通过应用程序事件(合成事件)派发该功能的应用程序,可以使用dispatchEvent()方法的返回值。

if(obj.dispatchEvent(event)) {
  // event was not canceled, time for some magic}

当一个事件派发到一个参与(例如,一个元素)的对象时,它也可以到达该对象的祖先上的事件监听器。实际上,该对象的所有包含祖先捕获为true的事件监听器都将按照树的顺序被调用。然后,如果事件bubbles为true,则该对象的所有包含祖先捕获为false的事件监听器将按照相反的树的顺序被调用。

让我们看一个事件中如何工作的例子:

<!doctype html>
<html>
 <head>
  <title>Boring example</title>
 </head>
 <body>
  <p>Hello <span id=x>world</span>!</p>
  <script>
   function test(e) {
     debug(e.target, e.currentTarget, e.eventPhase)
   }
   document.addEventListener("hey", test, {capture: true})
   document.body.addEventListener("hey", test)
   var ev = new Event("hey", {bubbles:true})
   document.getElementById("x").dispatchEvent(ev)
  </script>
 </body>
</html>

debug函数将被调用两次。每次事件target属性值将是span元素。第一次currentTarget属性值将是document,第二次将是body元素eventPhase属性值将从CAPTURING_PHASE切换到BUBBLING_PHASE。如果为span元素注册了一个事件监听器eventPhase属性值将是AT_TARGET

2.2. 接口 Event

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

  readonly attribute DOMString type;
  readonly attribute EventTarget? target;
  readonly attribute EventTarget? srcElement; // legacy
  readonly attribute EventTarget? currentTarget;
  sequence<EventTarget> composedPath();

  const unsigned short NONE = 0;
  const unsigned short CAPTURING_PHASE = 1;
  const unsigned short AT_TARGET = 2;
  const unsigned short BUBBLING_PHASE = 3;
  readonly attribute unsigned short eventPhase;

  undefined stopPropagation();
           attribute boolean cancelBubble; // legacy alias of .stopPropagation()
  undefined stopImmediatePropagation();

  readonly attribute boolean bubbles;
  readonly attribute boolean cancelable;
           attribute boolean returnValue;  // legacy
  undefined preventDefault();
  readonly attribute boolean defaultPrevented;
  readonly attribute boolean composed;

  [LegacyUnforgeable] readonly attribute boolean isTrusted;
  readonly attribute DOMHighResTimeStamp timeStamp;

  undefined initEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false); // legacy
};

dictionary EventInit {
  boolean bubbles = false;
  boolean cancelable = false;
  boolean composed = false;
};

一个Event对象通常被称为一个事件。它用于标识某些事情已经发生,例如,一个图像已经完成下载。

一个潜在事件目标是 null 或一个EventTarget对象。

一个事件有一个关联的目标(一个潜在事件目标)。除非另有说明,否则它为 null。

一个事件有一个关联的相关目标(一个潜在事件目标)。除非另有说明,否则它为 null。

其他规范使用相关目标来定义一个relatedTarget属性。[UIEVENTS]

一个事件有一个关联的触摸目标列表(一个列表,包含零个或多个潜在事件目标)。除非另有说明,否则它为空列表。

触摸目标列表专门用于定义TouchEvent接口和相关接口。[TOUCH-EVENTS]

一个事件有一个关联的路径。一个路径是一个列表,包含结构体。每个结构体由一个调用目标(一个EventTarget对象)、一个在 shadow 树中的调用目标(一个布尔值)、一个shadow 调整后的目标(一个潜在事件目标)、一个相关目标(一个潜在事件目标)、一个触摸目标列表(一个列表,包含潜在事件目标)、一个关闭树的根(一个布尔值)和一个关闭树中的插槽(一个布尔值)。一个路径最初为空列表。

event = new Event(type [, eventInitDict])
返回一个新的event,其type属性值设置为typeeventInitDict参数允许通过同名对象成员设置bubblescancelable属性。
event . type
返回event的类型,例如"click"、"hashchange"或"submit"。
event . target
返回event分派的对象(其目标)。
event . currentTarget
返回当前正在调用其事件侦听器回调函数的对象。
event . composedPath()
返回event调用目标对象(将在其上调用侦听器的对象),但不包括任何节点,这些节点在shadow 树中,其shadow root模式为"closed"且无法从eventcurrentTarget到达。
event . eventPhase
返回事件的阶段,它是以下之一:NONECAPTURING_PHASEAT_TARGETBUBBLING_PHASE
event . stopPropagation()
当在中分派时,调用此方法会阻止event到达当前对象以外的任何对象。
event . stopImmediatePropagation()
调用此方法会阻止event在当前侦听器运行结束后到达任何注册的事件侦听器,并且当在中分派时,也会阻止event到达任何其他对象。
event . bubbles
根据event的初始化方式返回 true 或 false。如果event通过其目标祖先按相反的树顺序传播,则为 true;否则为 false。
event . cancelable
根据event的初始化方式返回 true 或 false。其返回值并不总是有意义,但 true 可以表示在分派event的过程中,部分操作可以通过调用preventDefault()方法来取消。
event . preventDefault()
如果在cancelable属性值为 true 时调用,并且在执行带有passive设置为 false 的侦听器时,通知导致分派event的操作需要取消。
event . defaultPrevented
如果成功调用preventDefault()表示取消,则返回 true;否则返回 false。
event . composed
根据event的初始化情况返回 true 或 false。如果event调用了超过作为其目标ShadowRoot节点的监听器,则返回 true;否则返回 false。
event . isTrusted
如果event由用户代理分派,则返回 true,否则返回 false。
event . timeStamp
以毫秒为单位返回event的时间戳,相对于发生时间。

type属性必须返回初始化时的值。当创建一个事件时,必须将该属性初始化为空字符串。

target获取步骤是返回this目标

srcElement获取步骤是返回this目标

currentTarget属性必须返回初始化时的值。当创建一个事件时,必须将该属性初始化为 null。

composedPath()方法的步骤为:

  1. composedPath成为一个空的列表

  2. path成为this路径

  3. 如果path为空,则返回composedPath

  4. currentTarget成为thiscurrentTarget属性值。

  5. 断言currentTarget 是一个 EventTarget 对象。

  6. 追加currentTargetcomposedPath

  7. currentTargetIndex设为 0。

  8. currentTargetHiddenSubtreeLevel设为 0。

  9. index设为path大小 - 1。

  10. index大于或等于 0 时:

    1. 如果path[index]的关闭树的根为 true,则将currentTargetHiddenSubtreeLevel增加 1。

    2. 如果path[index]的调用目标currentTarget,则将currentTargetIndex设置为index,并中断

    3. 如果path[index]的关闭树中的插槽为 true,则将currentTargetHiddenSubtreeLevel减少 1。

    4. 减少index的值 1。

  11. currentHiddenLevelmaxHiddenLevel设为currentTargetHiddenSubtreeLevel

  12. index设为currentTargetIndex - 1。

  13. index大于或等于 0 时:

    1. 如果path[index]的关闭树的根为 true,则将currentHiddenLevel增加 1。

    2. 如果currentHiddenLevel小于或等于maxHiddenLevel,则前置path[index]的调用目标composedPath

    3. 如果 path[index] 的 slot-in-closed-tree 为 true:

      1. currentHiddenLevel减少 1。

      2. 如果currentHiddenLevel小于maxHiddenLevel,则将maxHiddenLevel设为currentHiddenLevel

    4. 减少index的值 1。

  14. currentHiddenLevelmaxHiddenLevel设为currentTargetHiddenSubtreeLevel

  15. index设为currentTargetIndex + 1。

  16. index小于path大小时:

    1. 如果path[index]的关闭树中的插槽为 true,则将currentHiddenLevel增加 1。

    2. 如果currentHiddenLevel小于或等于maxHiddenLevel,则追加path[index]的调用目标composedPath

    3. 如果 path[index] 的 root-of-closed-tree 为 true:

      1. currentHiddenLevel减少 1。

      2. 如果currentHiddenLevel小于maxHiddenLevel,则将maxHiddenLevel设为currentHiddenLevel

    4. 增加index的值 1。

  17. 返回composedPath

eventPhase属性必须返回初始化时的值,该值必须是以下之一:

NONE(数值 0)
事件当前未被分派时处于此阶段。
CAPTURING_PHASE(数值 1)
当一个事件分派到一个参与的对象时,它将在到达其目标之前处于此阶段。
AT_TARGET(数值 2)
当一个事件分派时,它将在其目标上处于此阶段。
BUBBLING_PHASE(数值 3)
当一个事件分派到一个参与的对象时,它将在到达其目标后处于此阶段。

最初该属性必须初始化为NONE


每个事件都具有以下关联标志,最初都未设置:

stopPropagation()方法的步骤是设置this停止传播标志

cancelBubble获取步骤是如果this停止传播标志已设置,则返回 true;否则返回 false。

cancelBubble设置步骤是如果给定值为 true,则设置this停止传播标志;否则不执行任何操作。

stopImmediatePropagation()方法的步骤是设置this停止传播标志this立即停止传播标志

bubblescancelable属性必须返回初始化时的值。

设置取消标志,给定一个事件event,如果eventcancelable属性值为 true 并且event在被动侦听器中的标志未设置,则设置event取消标志,否则不执行任何操作。

returnValue获取步骤是如果this取消标志已设置,则返回 false;否则返回 true。

returnValue设置步骤是如果给定值为 false,则设置取消标志,并将this作为参数;否则不执行任何操作。

preventDefault()方法的步骤是将取消标志设置为this

在某些情况下,调用preventDefault()无效。建议用户代理在开发者控制台中记录具体原因,以帮助调试。

defaultPrevented获取步骤是如果this取消标志已设置,则返回 true;否则返回 false。

composed获取步骤是如果this合成标志已设置,则返回 true;否则返回 false。


isTrusted属性必须返回初始化时的值。当创建一个事件时,必须将该属性初始化为 false。

isTrusted是一个方便的属性,指示一个事件是否由用户代理分派(而不是使用dispatchEvent())。唯一的传统例外是click(),它导致用户代理分派一个isTrusted属性初始化为 false 的事件

timeStamp属性必须返回初始化时的值。


初始化一个event,使用typebubblescancelable,运行以下步骤:

  1. 设置event初始化标志

  2. 取消设置event停止传播标志立即停止传播标志取消标志

  3. 设置eventisTrusted属性为 false。

  4. 设置event目标为 null。

  5. eventtype属性设置为type

  6. eventbubbles属性设置为bubbles

  7. eventcancelable属性设置为cancelable

initEvent(type, bubbles, cancelable)方法的步骤为:

  1. 如果this分派标志已设置,则返回。

  2. 初始化this,使用typebubblescancelable

initEvent()事件构造函数是多余的,并且无法设置composed。它必须为了遗留内容而支持。

2.3. Window 接口的传统扩展

partial interface Window {
  [Replaceable] readonly attribute (Event or undefined) event; // legacy
};

每个 Window 对象都有一个关联的 当前事件(未定义或一个 Event 对象)。除非另有说明,否则它是未定义的。

event 的 getter 步骤是返回 this当前事件

强烈建议 Web 开发者依赖传递给事件监听器的 Event 对象,因为这将产生更具可移植性的代码。此属性在 workers 或 worklets 中不可用,并且对于在 shadow trees 中分派的事件是不准确的。

2.4. 接口 CustomEvent

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

  readonly attribute any detail;

  undefined initCustomEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any detail = null); // legacy
};

dictionary CustomEventInit : EventInit {
  any detail = null;
};

事件 使用 CustomEvent 接口可以用于携带自定义数据。

event = new CustomEvent(type [, eventInitDict])
其工作方式类似于 Event 的构造函数,但 eventInitDict 参数现在还允许设置 detail 属性。
event . detail
返回创建 event 时的任何自定义数据。 通常用于合成事件。

detail 属性必须返回它初始化时的值。

initCustomEvent(type, bubbles, cancelable, detail) 方法的步骤如下:

  1. 如果 thisdispatch flag 已设置,则返回。

  2. 初始化 this ,包括 typebubblescancelable

  3. thisdetail 属性设置为 detail

2.5. 构造事件

规范可能会为所有或某些事件定义事件构造步骤。该算法接收一个事件event和一个EventIniteventInitDict,如内部事件创建步骤中所示。

这个构造方式可用于Event子类,它们具有比简单的初始化字典成员和IDL属性之间一对一映射更复杂的结构。

构造函数Event接口,或继承自Event接口的接口被调用时,必须运行以下步骤,给定参数typeeventInitDict

  1. 运行内部事件创建步骤,以获得event,使用此接口、null、当前时间和eventInitDict

  2. eventtype属性初始化为type

  3. 返回event

要使用eventInterface 创建事件,该接口必须是Event或继承自它的接口,并且可选地提供realm realm,运行以下步骤:

  1. 如果未提供realm,则将其设置为null。

  2. dictionary设置为将JavaScript值undefined转换为eventInterface构造函数所接受的字典类型的结果。(此字典类型将是EventInit或继承自它的字典类型。)

    如果需要成员,这种方法不起作用;请参见whatwg/dom#600

  3. 运行内部事件创建步骤,以eventInterfacerealm、该事件信号发生的时间和dictionary为参数,得到event

    在macOS中,输入操作的发生时间可以通过NSEvent对象的timestamp属性获得。

  4. eventisTrusted属性初始化为true。

  5. 返回event

创建事件用于需要分别创建分发事件的其他规范,而不是简单地触发事件。它确保事件的属性初始化为正确的默认值。

内部事件创建步骤,给定eventInterfacerealmtimedictionary,如下所示:

  1. 使用eventInterface创建一个新对象作为event的结果。如果realm非空,则使用该realm;否则,使用Web IDL中定义的默认行为。

    截至本文撰写时,Web IDL 尚未定义任何默认行为;请参见whatwg/webidl#135

  2. 设置event初始化标志

  3. eventtimeStamp属性初始化为给定timeevent相关全局对象相对高分辨率粗略时间

  4. 对于 dictionary 中的每个 membervalue: 如果 event 具有 标识符member 的属性,则将该属性初始化为 value

  5. 运行事件构造步骤,参数为eventdictionary

  6. 返回event

2.6. 定义事件接口

通常,在定义一个继承自Event的新接口时,请务必征求WHATWGW3C WebApps WG社区的反馈。

CustomEvent接口可以作为起点。然而,不要引入任何init*Event()方法,因为它们与构造函数是冗余的。继承自Event接口的接口中如果包含此类方法,也只是出于历史原因。

2.7. 接口 EventTarget

[Exposed=*]
interface EventTarget {
  constructor();

  undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {});
  undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {});
  boolean dispatchEvent(Event event);
};

callback interface EventListener {
  undefined handleEvent(Event event);
};

dictionary EventListenerOptions {
  boolean capture = false;
};

dictionary AddEventListenerOptions : EventListenerOptions {
  boolean passive;
  boolean once = false;
  AbortSignal signal;
};

一个 EventTarget 对象表示一个目标,当某些事情发生时,一个事件可以被派发到该目标。

每个 EventTarget 对象都有一个相关的事件监听器列表(一个由零个或多个事件监听器组成的列表)。它最初是空的列表。

一个事件监听器 可以用于观察特定的事件,它由以下部分组成:

虽然回调是一个 EventListener 对象,事件监听器 是一个更广泛的概念,如上所述。

每个 EventTarget 对象还有一个相关的获取父级算法, 该算法接收一个事件 event,并返回一个EventTarget 对象。除非另有说明,它返回null。

节点影子根节点文档会重写 获取父级算法。

每个 EventTarget 对象可以有一个相关的激活行为算法。该激活行为算法接收一个事件,如 派发 算法中所示。

这是因为用户代理在某些EventTarget 对象上执行某些操作,例如 area 元素,以响应其MouseEventtype 属性为click的合成事件。由于Web兼容性问题,它未能被移除,并且现在成为定义激活某些内容的固定方式。[HTML]

每个 EventTarget 对象如果具有激活行为,还可以同时(而非单独)具有遗留预激活行为算法 和遗留取消激活行为 算法。

这些算法仅存在于复选框和单选框的 input 元素中, 不适用于其他任何内容。[HTML]

target = new EventTarget();

创建一个新的EventTarget 对象,开发者可以使用它来派发并 监听事件

target . addEventListener(type, callback [, options])

type属性值为type事件附加一个事件侦听器callback参数设置将在事件分派时调用的回调函数

options为true时,监听器在捕获阶段触发;当为false或未设置时,监听器在冒泡阶段触发。无论设置如何,若事件处于目标阶段,监听器均会被触发。

options设置为true时,表示监听器为被动模式,不会调用preventDefault()来取消事件。

options设置为true时,表示监听器仅触发一次,触发后将被移除。

若为options指定了AbortSignal,当信号被中止时,监听器将被移除。

若已存在相同typecallbackcapture的事件监听器,则不会再次添加。

target . removeEventListener(type, callback [, options])

移除target中与typecallbackoptions匹配的事件监听器。

target . dispatchEvent(event)

派发event事件,并返回true,若事件的cancelable属性为false或未调用preventDefault(),否则返回false。

展开 options,请执行以下步骤:

  1. 如果options是布尔值,则返回options

  2. 返回options["capture"]。

进一步展开 options,请执行以下步骤:

  1. captureoptions展开的结果。

  2. once为false。

  3. passivesignal为null。

  4. 如果options是一个字典,则:

    1. once设置为options["once"]。

    2. 如果options["passive"] 存在,则将passive设置为options["passive"]。

    3. 如果options["signal"] 存在,则将signal设置为options["signal"]。

  5. 返回capturepassiveoncesignal

new EventTarget()构造函数步骤不执行任何操作。

由于其他地方声明的默认值,返回的EventTarget获取父级算法将返回null,并且它没有激活行为遗留预激活行为, 或遗留取消激活行为

将来我们可能会允许自定义获取父级算法。请告诉我们 这对您的程序是否有用。目前,所有作者创建的EventTarget 不参与树结构。

默认被动值,给定一个事件类型type和一个EventTarget eventTarget,由下列步骤决定:

  1. 若下列条件全部满足,则返回true:

  2. 返回false。

添加事件监听器,给定一个EventTarget 对象eventTarget和一个事件监听器listener,请执行以下步骤:

  1. eventTarget是一个ServiceWorkerGlobalScope 对象,其service worker脚本资源曾经评估过的标志被设置,且listener类型与任何service worker 事件类型属性值匹配,则向控制台报告一个警告,提示这可能不会产生预期结果。[SERVICE-WORKERS]

  2. 如果 listenersignal 不为 null 并且已中止,则返回。

  3. listener回调为null,则返回。

  4. listener被动为null,则将其设置为listener默认被动值,根据listener类型eventTarget

  5. eventTarget事件监听器列表包含一个事件监听器,其类型listener类型回调listener回调,且捕获listener捕获,则追加 listenereventTarget事件监听器列表中。

  6. listener信号不为null,则添加以下中止步骤:

    1. 移除事件监听器,使用eventTargetlistener

添加事件监听器的概念是为了确保事件处理器使用相同的代码路径。[HTML]

addEventListener(type, callback, options) 方法步骤为:

  1. capturepassiveoncesignal进一步展开 options的结果。

  2. 添加事件监听器,使用this和一个事件监听器,其类型type回调callback捕获capture被动passive一次性once信号signal

移除事件监听器,给定一个EventTarget 对象eventTarget和一个事件监听器 listener,请执行以下步骤:

  1. 如果eventTargetServiceWorkerGlobalScope对象,并且它的Service Worker要处理的事件类型集合包含listener类型,那么报告一个警告到控制台,表明这可能不会产生预期的结果。[SERVICE-WORKERS]

  2. listenerremoved设置为true,并且eventTarget事件侦听器列表中移除listener

HTML 需要这个来定义事件处理器。[HTML]

移除所有事件监听器,给定一个EventTarget 对象eventTarget: 对其每个 listener事件监听器列表项: 移除事件监听器,使用eventTargetlistener

HTML 需要这个来定义document.open()[HTML]

removeEventListener(type, callback, options) 方法步骤为:

  1. capture展开options的结果。

  2. 如果this事件 监听器列表 包含一个事件监听器, 其类型type回调callback,且捕获capture,则移除事件监听器,使用this和该事件监听器

事件侦听器列表不会包含具有相同typecallbackcapture的多个事件侦听器,因为添加事件侦听器会防止这种情况发生。

dispatchEvent(event)方法步骤为:

  1. event派发标志已设置,或其初始化标志未设置,则抛出一个“InvalidStateErrorDOMException

  2. eventisTrusted属性初始化为false。

  3. 返回派发 eventthis的结果。

2.8. 观察事件监听器

一般来说,开发者不会期望事件监听器的存在是可观察的。 事件监听器的影响由其回调决定。也就是说, 开发者添加一个无操作的事件监听器时不会期望它有任何副作用。

不幸的是,一些事件API的设计使得要高效实现它们就需要观察事件侦听器。这使得侦听器的存在是可观察的,即使是空的侦听器也可能对应用程序的行为产生显著的性能影响。例如,可以用于阻止异步滚动的触摸和滚轮事件。在某些情况下,可以通过仅在存在至少一个非被动侦听器时将事件指定为可取消来缓解这一问题。例如,非被动触摸事件侦听器必须阻止滚动,但如果所有侦听器都是被动的,则可以通过使触摸事件不可取消(从而忽略对preventDefault()的调用)来允许滚动并行开始。因此,分派事件的代码能够观察到非被动侦听器的缺失,并使用该信息来清除正在分派的事件的可取消属性。

理想情况下,任何新的事件API都应定义为不需要此属性。(请使用whatwg/dom进行讨论。)

获取遗留的Service Worker获取事件侦听器回调,给定一个ServiceWorkerGlobalScopeglobal,请运行以下步骤。这些步骤将返回一个EventListener对象的列表

  1. callbacks 为 « »。

  2. 对于每一个 listener 属于 global事件监听器列表:如果 listener类型为 "fetch" 并且 listener回调 不为 null, 则 listener回调添加到 callbacks

  3. 返回 callbacks

2.9. 分发事件

要将一个事件分发给一个目标,可选带有legacy target override flaglegacyOutputDidListenersThrowFlag,请按以下步骤操作:

  1. 设置event分发标志

  2. 如果未给出legacy target override flag,则将targetOverride设置为目标,否则设置为目标关联的文档[HTML]

    legacy target override flag仅由HTML使用,且仅当目标是一个窗口对象时使用。

  3. activationTarget设置为null。

  4. relatedTarget设置为针对目标重新定位eventrelatedTarget的结果。

  5. clearTargets 为 false。

  6. 如果 target 不是 relatedTarget 或者 targeteventrelatedTarget

    1. touchTargets设置为一个新的列表

    2. 对于每个touchTarget,它在event触摸目标列表中: 追加针对目标重新定位touchTarget的结果到touchTargets中。

    3. 通过event目标targetOverriderelatedTargettouchTargets,并设置为false,附加到事件路径

    4. 如果event是一个鼠标事件对象,且event类型属性为"click",则isActivationEvent为true;否则为false。

    5. 如果isActivationEvent为true且目标具有激活行为,则将activationTarget设置为目标

    6. 如果目标是一个slottable且已分配,则将slottable设置为目标,否则为null。

    7. slot-in-closed-tree设置为false。

    8. parent设置为调用目标获取父项结果的event

    9. parent非空时:

      1. 如果slottable非空:

        1. 断言:parent是一个插槽

        2. slottable设置为null。

        3. 如果parent是一个影子根,且它的模式是"closed",则将slot-in-closed-tree设置为true。

      2. 如果parent是一个slottable且已分配,则将slottable设置为parent

      3. relatedTarget设置为针对parent重新定位eventrelatedTarget的结果。

      4. touchTargets设置为一个新的列表

      5. 对于每个touchTarget ,它在event触摸目标列表中: 追加针对parent重新定位touchTarget的结果到touchTargets中。

      6. 如果parent是一个窗口对象,或parent是一个节点目标parent包括影子在内的包容性祖先,则:

        1. 如果isActivationEvent为true,event冒泡属性为true,activationTarget为null,且parent具有激活行为,则将activationTarget设置为parent

        2. 附加到事件路径通过eventparent、null、relatedTargettouchTargets,并设置slot-in-closed-tree

      7. 否则,如果parentrelatedTarget,则将parent设置为null。

      8. 否则:

        1. 目标设置为parent

        2. 如果isActivationEvent为true,activationTarget为null,且目标具有激活行为,则将activationTarget设置为目标

        3. 附加到事件路径通过eventparent目标relatedTargettouchTargets,并设置slot-in-closed-tree

      9. 如果parent非空,则将parent设置为调用parent获取父项结果的event

      10. slot-in-closed-tree设置为false。

    10. clearTargetsStruct设置为event路径中的最后一个结构,其影子调整目标非空。

    11. 如果 clearTargetsStructshadow-adjusted targetclearTargetsStructrelatedTarget,或 clearTargetsStructtouch target list 中的 EventTarget 对象是一个节点,其是一个影子根:则将 clearTargets 设置为 true。

    12. 如果activationTarget非空且activationTarget具有旧式预激活行为,则运行activationTarget旧式预激活行为

    13. 对于 eventpath 中的每个 struct,按相反顺序:

      1. 如果struct影子调整目标非空,则 将event事件阶段属性设置为AT_TARGET

      2. 否则,将event事件阶段属性设置为CAPTURING_PHASE

      3. 调用通过structevent、"捕获",以及如果给出的话legacyOutputDidListenersThrowFlag

    14. 对于 eventpath 中的每个 struct

      1. 如果struct影子调整目标非空,则 将event事件阶段属性设置为AT_TARGET

      2. 否则:

        1. 如果event冒泡属性为false,则继续

        2. event事件阶段属性设置为BUBBLING_PHASE

      3. 调用通过structevent、"冒泡",以及如果给出的话legacyOutputDidListenersThrowFlag

  7. event事件阶段属性设置为NONE

  8. event当前目标属性设置为null。

  9. event路径设置为空列表。

  10. 取消设置event分发标志停止传播标志,以及立即停止传播标志

  11. 如果 clearTargets 为 true:

    1. event目标设置为null。

    2. eventrelatedTarget设置为null。

    3. event触摸目标列表设置为空列表。

  12. 如果activationTarget非空:

    1. 如果event取消标志未设置,则使用event运行activationTarget激活行为

    2. 否则,如果activationTarget具有旧式取消激活行为,则运行activationTarget旧式取消激活行为

  13. 如果event取消标志已设置,则返回false;否则返回true。

附加到事件路径,给定一个eventinvocationTargetshadowAdjustedTargetrelatedTargettouchTargets,以及slot-in-closed-tree,请运行这些步骤:

  1. invocationTargetInShadowTree设置为false。

  2. 如果invocationTarget是一个节点,且其是一个影子根,则将invocationTargetInShadowTree设置为true。

  3. root-of-closed-tree设置为false。

  4. 如果invocationTarget是一个影子根,且其模式是"closed",则将root-of-closed-tree设置为true。

  5. 追加一个新的结构event路径,其调用目标invocationTarget调用目标在影子树中invocationTargetInShadowTree影子调整目标shadowAdjustedTargetrelatedTargetrelatedTarget触摸目标列表touchTargets关闭树的根root-of-closed-tree,以及slot-in-closed-treeslot-in-closed-tree

调用,给定一个structevent阶段,以及可选的legacyOutputDidListenersThrowFlag,请运行这些步骤:

  1. event目标设置为event路径中的最后一个结构,其影子调整目标非空,且为structstruct之前的结构。

  2. eventrelatedTarget设置为structrelatedTarget

  3. event触摸目标列表设置为struct触摸目标列表

  4. 如果event停止传播标志已设置,则返回。

  5. 初始化event当前目标属性为struct调用目标

  6. listeners设置为event当前目标属性值的事件侦听器列表克隆

    这避免了在此点之后添加的事件侦听器被运行。请注意,由于已删除字段,移除仍然有影响。

  7. invocationTargetInShadowTree设置为struct调用目标在影子树中

  8. found设置为运行内部调用通过eventlisteners阶段invocationTargetInShadowTree,以及如果给出的话legacyOutputDidListenersThrowFlag的结果。

  9. 如果 found 为 false 且 eventisTrusted 属性为 true:

    1. originalEventType设置为event类型属性值。

    2. 如果event类型属性值匹配下表中的任意字符串,将event类型属性值设置为同一行匹配字符串旁的字符串,否则返回。

      事件类型 旧式事件类型
      "animationend" "webkitAnimationEnd"
      "animationiteration" "webkitAnimationIteration"
      "animationstart" "webkitAnimationStart"
      "transitionend" "webkitTransitionEnd"
    3. 内部调用通过eventlisteners阶段invocationTargetInShadowTree,以及如果给出的话legacyOutputDidListenersThrowFlag

    4. event类型属性值设置为originalEventType

内部调用,给定一个eventlisteners阶段invocationTargetInShadowTree,以及可选的legacyOutputDidListenersThrowFlag,请运行这些步骤:

  1. found 为 false。

  2. 对于 listeners 中的每个 listener,其 removed 为 false:

    1. 如果 eventtype 属性值不是 listener类型,则 继续

    2. found 设为 true。

    3. 如果 phase 是 "capturing" 并且 listenercapture 为 false,则 继续

    4. 如果 phase 是 "bubbling" 并且 listenercapture 为 true,则 继续

    5. 如果 listeneronce 为 true,则根据 eventcurrentTarget 属性值和 listener 移除一个事件侦听器

    6. global 成为 listener回调关联的领域全局对象

    7. currentEvent 为 undefined。

    8. 如果 global 是一个 Window 对象:

      1. currentEvent 设为 global当前事件

      2. 如果 invocationTargetInShadowTree 为 false,则将 global当前事件 设为 event

    9. 如果 listenerpassive 为 true,则设定 event被动监听器标志

    10. 如果 global 是一个 Window 对象,则 记录事件监听器的计时信息,使用 eventlistener

    11. 调用用户对象的操作,使用 listener回调,"handleEvent",«event»,以及 eventcurrentTarget 属性值。如果这会抛出一个异常 exception

      1. 报告 exception,用于 listener回调的相应 JavaScript 对象的 关联领域全局对象

      2. 设置 legacyOutputDidListenersThrowFlag(如果提供)。

        legacyOutputDidListenersThrowFlag 仅被 Indexed Database API 使用。[INDEXEDDB]

    12. 取消设定 event被动监听器标志

    13. 如果 global 是一个 Window 对象,则将 global当前事件 设为 currentEvent

    14. 如果 event停止立即传播标志已设置,则中断

  3. 返回 found

2.10. 触发事件

要在target触发事件,事件名为e,可选地使用eventConstructor,并描述如何初始化IDL属性,以及legacy target override flag,请执行以下步骤:

  1. 如果未给出eventConstructor,则令eventConstructorEvent

  2. event为根据eventConstructor 创建事件的结果,且在target相关领域中。

  3. eventtype属性初始化为e

  4. 按照此算法调用时描述的内容初始化event的其他IDL属性。

    这也允许将isTrusted属性设置为false。

  5. 返回调度eventtarget的结果,并在设置时设置legacy target override flag

在 DOM 的上下文中,"Fire" 是创建、初始化和分派一个事件的缩写。Fire an event 使得这个过程更容易表达。

如果事件需要其 bubblescancelable 属性初始化, 可以这样写:“fire an event named submit at target with its cancelable attribute initialized to true”。

或者,当需要自定义构造函数时,可以这样写:“fire an event named click at target using MouseEvent with its detail attribute initialized to 1”。

有时返回值很重要:

  1. doAction 成为 firing an event named like at target 的结果。

  2. 如果 doAction 为真,那么……

2.11. 行为与发生

一个事件表示一次发生,而不是一个行为。换句话说,它 代表来自算法的通知,并可用于影响该算法的未来进程 (例如,通过调用 preventDefault())。 事件不得 用作导致某些算法开始运行的行为或发起者。那不是 它们的用途。

在此特别指出这一点,是因为 DOM 的先前迭代具有与事件关联的“默认行为”概念,这给人们带来了所有错误的想法。事件不代表或导致行为,它们 只能用于影响正在进行的行为。

3. 中止正在进行的活动

尽管 promise 没有内置的中止机制,但许多使用它们的 API 都需要中止语义。AbortController 旨在通过提供一个 abort() 方法来支持这些要求,该方法可以切换相应 AbortSignal 对象的状态。希望支持中止的 API 可以接受一个 AbortSignal 对象,并使用其状态来确定如何继续。

鼓励依赖 AbortController 的 API 通过使用 AbortSignal中止原因来拒绝任何未解决的 promise,从而响应 abort()

一个假设的doAmazingness({ ... })方法可以通过接受AbortSignal对象来支持中止,类似如下:

const controller = new AbortController();
const signal = controller.signal;

startSpinner();

doAmazingness({ ..., signal })
  .then(result => ...)
  .catch(err => {
    if (err.name == 'AbortError') return;
    showUserErrorMessage();
  })
  .then(() => stopSpinner());

// …

controller.abort();

doAmazingness could be implemented as follows:

function doAmazingness({signal}) {
  return new Promise((resolve, reject) => {
    signal.throwIfAborted();

    // Begin doing amazingness, and call resolve(result) when done.
    // But also, watch for signals:
    signal.addEventListener('abort', () => {
      // Stop doing amazingness, and:
      reject(signal.reason);
    });
  });
}

不返回promise的API可以选择以类似的方式做出反应,或者选择完全不展示AbortSignal中止原因addEventListener()就是一个适合后者的API例子。

需要更精细控制的API可以根据需要扩展AbortControllerAbortSignal对象。

3.1. 接口 AbortController

[Exposed=*]
interface AbortController {
  constructor();

  [SameObject] readonly attribute AbortSignal signal;

  undefined abort(optional any reason);
};
controller = new AbortController()
返回一个新的controller,其signal被设置为新创建的AbortSignal对象。
controller . signal
返回与此对象关联的AbortSignal对象。
controller . abort(reason)
调用此方法将把reason存储在此对象的AbortSignal中止原因中,并向任何观察者发出信号,表示相关活动将被中止。如果reason未定义,则会存储一个"AbortError"DOMException

一个AbortController对象有一个关联的信号(一个AbortSignal对象)。

new AbortController()构造函数步骤如下:

  1. signal成为一个新的AbortSignal对象。

  2. 设置thissignalsignal

signal的getter步骤是返回thissignal

abort(reason)方法步骤是在signal abort上执行,带有reason如果给定。

AbortControllercontroller上带有可选的reason执行signal abort,如果reason被提供。

3.2. 接口AbortSignal

[Exposed=*]
interface AbortSignal : EventTarget {
  [NewObject] static AbortSignal abort(optional any reason);
  [Exposed=(Window,Worker), NewObject] static AbortSignal timeout([EnforceRange] unsigned long long milliseconds);
  [NewObject] static AbortSignal _any(sequence<AbortSignal> signals);

  readonly attribute boolean aborted;
  readonly attribute any reason;
  undefined throwIfAborted();

  attribute EventHandler onabort;
};
AbortSignal . abort(reason)
返回一个AbortSignal实例,其中止原因设置为reason(如果未定义则为"AbortError"DOMException)。
AbortSignal . any(signals)
返回一个AbortSignal实例,该实例将在任一signals中止时中止。其中止原因将被设置为导致中止的signals中的某一个。
AbortSignal . timeout(milliseconds)
返回一个AbortSignal实例,该实例将在milliseconds毫秒后中止。其中止原因将被设置为"TimeoutError"DOMException
signal . aborted
如果signalAbortController已发出中止信号,则返回true;否则返回false。
signal . reason
返回signal中止原因
signal . throwIfAborted()
如果signalAbortController已发出中止信号,则抛出signal中止原因;否则不执行任何操作。

一个AbortSignal对象有一个关联的中止原因(一个JavaScript值),其初始状态为未定义。

一个AbortSignal对象有一个关联的中止算法(一组将在中止时执行的算法),其初始状态为空。

中止算法使得具有复杂要求的API能够合理地响应abort()。例如,给定API的中止原因可能需要传播到跨线程环境,例如service worker。

一个AbortSignal对象有一个依赖项(一个布尔值),其初始状态为false。

一个AbortSignal对象有一个关联的源信号(一组AbortSignal对象),其初始状态为空。

一个AbortSignal对象有一个关联的依赖信号(一组依赖于对象的AbortSignal对象),其初始状态为空。


静态方法abort(reason)的步骤如下:

  1. signal成为一个新的AbortSignal对象。

  2. signal中止原因设置为reason,如果给定;否则设置为新的"AbortError"DOMException

  3. 返回signal

静态方法timeout(milliseconds)的步骤如下:

  1. signal成为一个新的AbortSignal对象。

  2. global成为signal相关全局对象

  3. 在超时后运行步骤,给定global、"AbortSignal-timeout"、milliseconds,以及以下步骤:

    1. 在全局任务队列中排队,在global上,基于signal和新的"TimeoutError"DOMException执行signal abort

    在此超时时间内,如果signal已为其abort事件注册了任何事件监听器,则必须从globalsignal保持一个强引用。

  4. 返回signal

静态方法any(signals)的步骤是返回创建一个依赖的中止信号的结果,使用signalsAbortSignal当前领域

abortedgetter步骤是返回true如果this中止;否则返回false。

reasongetter步骤是返回this中止原因

throwIfAborted()方法步骤是抛出this中止原因,如果this中止

此方法主要用于当接受AbortSignal的函数希望在特定检查点抛出(或返回一个被拒绝的promise),而不是将AbortSignal传递给其他方法时。例如,以下函数允许在每次尝试轮询条件之间中止。这为中止轮询过程提供了机会,即使实际的异步操作(即await func())不接受AbortSignal

async function waitForCondition(func, targetValue, { signal } = {}) {
  while (true) {
    signal?.throwIfAborted();

    const result = await func();
    if (result === targetValue) {
      return;
    }
  }
}

属性 onabort 是一个 事件处理程序 IDL 属性,用于 onabort 事件处理程序,其 事件处理程序事件类型abort

AbortSignal 对象的更改代表了相应的 AbortController 对象的意图,但观察 AbortSignal 对象的 API 可以选择忽略这些更改。例如,如果操作已经完成。


AbortSignal 对象的 中止原因 不为未定义时, 该对象被认为是 已中止

要向 AbortSignal 对象 signal添加 一个算法 algorithm

  1. 如果 signal中止,则返回。

  2. algorithm 追加到 signal中止算法中。

要从 AbortSignal signal移除一个算法 algorithm,请从 signal中止算法移除 algorithm

发出中止信号, 给定一个 AbortSignal 对象 signal 和一个可选的 reason

  1. 如果 signal 已经 中止,则返回。

  2. signal中止原因 设为 reason(如果提供);否则设为一个新的 "AbortError" DOMException

  3. dependentSignalsToAbort 设为一个新的 列表

  4. 对于每个 dependentSignalsignal依赖信号 中:

    1. 如果 dependentSignal 尚未 中止

      1. dependentSignal中止原因 设为 signal中止原因

      2. 附加 dependentSignaldependentSignalsToAbort

  5. 运行中止步骤 对于 signal

  6. 对于每个 dependentSignaldependentSignalsToAbort 中,运行中止步骤 对于 dependentSignal

运行中止步骤 对于一个 AbortSignal signal

  1. 对于每个 algorithmsignal中止算法 中:运行 algorithm

  2. 清空 signal中止算法

  3. 触发事件,名为 abort,在 signal 上。

要从 AbortSignal 对象列表 signals 创建一个依赖中止信号,使用 signalInterface(它必须是 AbortSignal 或继承自它的接口)和一个 realm

  1. resultSignal 为一个使用 realm 实现 signalInterface对象。

  2. 对于 signals 中的每个 signal:如果 signal中止,则将 resultSignal中止原因设置为 signal中止原因并返回 resultSignal

  3. resultSignal依赖属性设置为 true。

  4. 对于 signals 中的每个 signal

    1. 如果 signal依赖属性为 false:

      1. signal 追加resultSignal源信号列表中。

      2. resultSignal 追加signal依赖信号列表中。

    2. 否则,对于 signal源信号列表中的每个 sourceSignal

      1. 断言:sourceSignal中止 且其依赖属性不为 true。

      2. sourceSignal 追加resultSignal源信号列表中。

      3. resultSignal 追加sourceSignal依赖信号列表中。

  5. 返回 resultSignal

3.2.1. 垃圾回收

一个未中止依赖的 AbortSignal 对象,当其源信号列表非空并且它已为其 abort 事件注册了事件监听器或者其中止算法列表非空时,不能被垃圾回收。

3.3. 在 API 中使用 AbortControllerAbortSignal 对象

任何使用 promises 表示可以中止操作的 Web 平台 API 必须遵循以下规则:

返回 promise 的方法 doAmazingness(options) 的方法步骤可能如下:

  1. global成为相关全局对象

  2. p成为一个新的 promise

  3. 如果 options["signal"] 存在

    1. signal成为options["signal"]。

    2. 如果 signal已中止, 则拒绝p,使用signal中止原因,并返回 p

    3. 添加以下中止步骤signal

      1. 停止做令人惊叹的事情。

      2. 拒绝p,使用signal中止原因

  4. 并行运行这些步骤:

    1. amazingResult成为做一些令人惊叹的事情的结果。

    2. 在全局任务队列中添加一个任务,任务源为global,以解决p,并将amazingResult作为参数。

  5. 返回 p

不使用 promises 的 API 仍应尽可能遵循上述规则。

4. 节点

4.1. “DOM”简介

在其原始意义上,“DOM”是一个用于访问和操作文档(特别是HTML和XML文档)的API。在本规范中,术语“文档”用于任何基于标记的资源,从简短的静态文档到包含丰富多媒体的长篇文章或报告,以及功能齐全的交互式应用程序。

每个这样的文档都表示为一个节点树中的一些节点可以有子节点,而其他的总是叶子节点。

为了说明这一点,考虑以下HTML文档:

<!DOCTYPE html>
<html class=e>
 <head><title>Aliens?</title></head>
 <body>Why yes.</body>
</html>

它表示如下:

请注意,由于HTML解析的神奇之处,并非所有ASCII空白字符都被转化为文本节点,但总体概念是清晰的。标记进入,节点输出。

可以使用非常棒的Live DOM Viewer来更详细地探索这个问题。

4.2. 节点树

节点是实现了实现Node的对象。节点参与一个称为节点树

实际上,你处理的是更具体的对象。

实现了实现Node的对象也实现了一个继承的接口:DocumentDocumentTypeDocumentFragmentElementCharacterDataAttr

实现了DocumentFragment的对象有时会实现ShadowRoot

实现了Element的对象通常也会实现一个继承的接口,例如HTMLAnchorElement

实现了CharacterData的对象也会实现一个继承的接口:TextProcessingInstructionComment

实现了Text的对象有时会实现CDATASection

因此,每个节点主要接口是以下之一:DocumentDocumentTypeDocumentFragmentShadowRootElementElement的一个继承接口,AttrTextCDATASectionProcessingInstructionComment

为简洁起见,本规范将实现了Node和继承接口NodeInterface的对象称为NodeInterface节点

节点树的限制如下,表示为节点及其潜在子节点之间的关系:

Document

树顺序

  1. 零个或多个ProcessingInstructionComment节点

  2. 可选地包含一个DocumentType节点

  3. 零个或多个ProcessingInstructionComment节点

  4. 可选地包含一个Element节点

  5. 零个或多个ProcessingInstructionComment节点

DocumentFragment
Element

零个或多个ElementCharacterData节点

DocumentType
CharacterData
Attr

没有子节点

Attr 节点因历史原因会参与一棵;它们从不会有(非 null)父节点或任何子节点,因此始终独自处于一棵中。

要确定节点node长度,执行以下步骤:

  1. 如果nodeDocumentTypeAttr节点,则返回 0。

  2. 如果nodeCharacterData 节点,则返回 nodedata长度

  3. 返回 node子节点数量。

节点长度为 0 时,认为该节点是空的

4.2.1. 文档树

文档树是一个节点树,其是一个文档

文档元素是一个文档中其父节点是该文档元素;如果不存在,则为 null。

根据节点树的限制,这样的元素只能有一个。

当一个节点文档时,称该节点处于文档树中

当一个节点处于文档树中时,称其处于文档中术语处于文档中已不再建议使用,若存在该术语,说明所用标准尚未更新以适配影子树

4.2.2. 影子树

影子树是一个节点树,其是一个影子根

影子根总是通过其宿主附加到另一个节点树。因此,影子树永远不会是孤立的。影子根宿主节点树有时被称为光树

一个影子树的相应光树本身可以是一个影子树

当一个节点包含影子的根是一个文档时,该节点被认为是已连接的

4.2.2.1. 插槽

一个影子树包含零个或多个元素,它们是插槽

一个插槽只能通过HTML的slot元素创建。

一个插槽有一个关联的名称(一个字符串)。除非另有说明,否则它是空字符串。

使用这些属性更改步骤来更新一个插槽名称

  1. 如果element是一个插槽localNamename,且namespace为空:

    1. 如果valueoldValue,则返回。

    2. 如果value为null且oldValue为空字符串,则返回。

    3. 如果value为空字符串且oldValue为null,则返回。

    4. 如果value为null或空字符串,则将element名称设置为空字符串。

    5. 否则,将element名称设置为value

    6. 使用element运行为树分配可插槽对象

一个插槽是一个影子树中的第一个,在树顺序中,其名称为空字符串的插槽,有时被称为“默认插槽”。

一个插槽有一个关联的分配的节点(一个可插槽对象的列表)。除非另有说明,否则它是空的。

4.2.2.2. 可插槽对象