参与者组织方式

简而言之:根参与者 (Root actor) 公开了描述可调试上下文的描述符参与者 (Descriptor actors)。描述符参与者随后公开一个专用的观察者参与者 (Watcher actor)。观察者参与者会通知许多目标参与者(每个较小的可调试上下文一个:WindowGlobal、worker 等),还会通知所有资源(控制台消息、源代码、网络事件等)。

首先,参与者存在于 devtools/server/actors 文件夹中。它们以层次结构组织,以便于生命周期和内存管理:一旦父参与者从池中移除,其子参与者也会被移除。(有关如何实现新的参与者的更多信息,请参阅 actor-registration.md

参与者的整体层次结构如下所示

 ###  RootActor:
  |
  |   First one, automatically instantiated when we start connecting
  |   with a fixed actor ID set to "root".
  |
  |   It is mostly meant to instantiate all the following actors.
  |
  |-- Global-scoped actors:
  |
  |   Actors exposing features related to the main process, that are not
  |   specific to any particular target (document, tab, add-on, or worker).
  |   These actors are registered with `global: true` in:
  |     devtools/server/actors/utils/actor-registry.js
  |
  |   Examples:
  |     * PreferenceActor (for Firefox prefs)
  |     * DeviceActor (for fetching and toggling runtime specifics)
  |     * PerfActor (used by the profiler.firefox.com profiler)
  |     * ...
  |
  \-- Descriptor actors
   |
   |  These actors expose information about a particular context that DevTools can focus on:
   |    * a tab (TabDescriptor)
   |    * a (service/shared/chrome) worker (WorkerDescriptor)
   |    * a Web Extension (WebExtensionDescriptor)
   |    * the browser (ProcessDescriptor)
   |
   |   This actor is mostly informative. It exposes a WatcherActor to actually debug this context.
   |   This is typically used by about:debugging to display all available debuggable contexts.
   |
   \ -- WatcherActor
     |
     |   Each descriptor actor exposes a dedicated Watcher actor instance.
     |   This actor allows to observe target actors and resources.
     |
     \ -- Target actors:
       |
       |  Within a given descriptor/watcher context, targets represents fine grained debuggable contexts.
       |  While the descriptor and watcher stays alive until the devtools are closed or the debuggable context
       |  was close (tab closed, worker destroyed or browser closed),
       |  the targets have a shorter lifecycle and a narrowed scope.
       |
       |  The typical target actors are WindowGlobal target actors.
       |  This represents one specific WindowGlobal. A tab is typically made of many of them.
       |  Each iframe will have its dedicated WindowGlobal.
       |  Each navigation will also spawn a new dedicated WindowGlobal.
       |  When debugging an add-on, you will have one WindowGlobal target for the background page,
       |  one for each popup, ...
       |
       |  The other targets actors are:
       |    * worker targets
       |    * process targets (only used in the Browser Toolbox to debug the browser itself made of many processes)
       |
       \ -- Target-scoped actors:

            Actors exposing one particular feature set. They are children of a
            given target actor and the data they return is filtered to reflect
            the target.
            These actors are registered with `target: true` in
              devtools/server/actors/utils/actor-registry.js

            Examples:
              * WebConsoleActor (for evaluating javascript)
              * InspectorActor (to observe and modify the DOM Elements)
              * ThreadActor (for setting breakpoints and pause/step/resume)
              * StorageActor (for managing storage data)
              * AccessibilityActor (to observe accessibility information)

            These actors may extend this hierarchy by having their own children,
            like LongStringActor, WalkerActor, SourceActor, NodeActor, etc.

根参与者 (RootActor)

根参与者是特殊的。它在客户端连接时自动创建。它有一个特殊的 actorID,它是唯一的,并且是“root”。所有其他参与者都具有动态计算的 actorID,因此您需要请求现有参与者创建参与者并返回其 actorID。这是 RootActor 的主要作用。它将公开所有描述符参与者,这仅仅是生成观察者、目标和目标范围参与者的开始。

RootActor (root.js)
   |
   |-- TabDescriptorActor (descriptors/tab.js)
   |
   |   Designates tabs running in the parent or child process.
   |
   |   Returned by "listTabs" or "getTab" requests.
   |
   |-- WorkerDescriptorActor (descriptors/worker.js)
   |
   |   Designates any type of worker: web worker, service worker, shared worker, chrome worker.
   |
   |   Returned by "listWorkers" request to the root actor to get all workers. (/!\ this is an expensive method)
   |   Returned by "listWorkers" request to a WindowGlobalTargetActor to get
   |   workers for a specific document/WindowGlobal. (this is a legacy, to be removed codepath)
   |   Returned by "listWorkers" request to a ContentProcessTargetActor to get
   |   workers for the chrome of the child process. (this is a legacy, to be removed codepath)
   |
   |-- ParentProcessDescriptorActor (descriptors/process.js)
   |
   |   Designates any parent or content processes.
   |   This exposes all chrome documents, JSMs/ESMs, JS XPCOM, etc.
   |
   |   Returned by "listProcesses" and "getProcess".
   |
   \-- WebExtensionDescriptorActor (descriptors/webextension.js)

       Designates a WebExtension add-on in the parent process. This gives some
       metadata about the add-on and watches for uninstall events.

       Returned by "listAddons" request.

所有这些描述符参与者都公开了一个 getTarget() 方法,该方法返回描述符的可调试上下文的目标参与者。

但请注意,这现在被认为是已弃用的代码路径。理想情况下,所有目标都应通过新的 WatcherActor 获取。目前,WatcherActor 仅支持标签和整个浏览器的调试。Worker 和附加组件仍然必须通过描述符的 getTarget 进行访问。

观察者参与者 (Watcher Actors)

每个描述符都公开一个专用的观察者参与者(通过 getWatcher RDP 方法),该参与者作用域限定为描述符的可调试上下文。

此参与者负责观察事物。它将通知您有关

  • 目标参与者,通过 target-available-form 和 target-destroyed-form 事件,

  • 资源,通过 resources-available-array、resources-updated-array 和 resources-destroyed-array 事件。

资源

资源不一定是参与者。它们可以是简单的 JSON 对象,描述 Web 的特定部分。资源可以描述控制台消息、JS 源代码、网络事件等。

每个资源都由一个专用的 ResourceWatcher 类进行观察,该类在 devtools/server/actors/resources/ 中实现,其中 index.js 注册所有资源类型。

这些 ResourceWatcher 类应实现一个 watch() 方法来开始监视给定资源类型,以及一个 destroy() 方法来停止监视。每次我们开始监视给定类型时,都会实例化一个新的实例。

这些类可以通过多种方式实例化

  • 仅从父进程,如果资源只能从那里观察(例如:网络事件和某些存储)。在这种情况下,watch 方法将接收一个观察者参与者作为参数。

  • 仅从目标线程,这可以是标签线程或工作线程。在这种情况下,watch 方法将接收一个目标参与者作为参数。

目标参与者 (Target Actors)

这些是观察者参与者 target-available-form 事件公开的参与者,或者通过描述符的 getTarget() 方法公开的参与者。它们旨在跟踪描述符上下文非常精确的可调试部分的生命周期

  • 一个精确的文档实例,也称为 WindowGlobal

  • 一个 Worker,

  • 一个父进程或内容进程。

其主要目的是公开目标范围参与者 ID,所有这些 ID 都包含在目标表单中。目标表单由观察者参与者 target-available-form 事件公开(或通过现在已弃用的描述符的 getTarget() 方法公开)。

一旦相关的可调试上下文消失,目标就会被销毁。

由于历史原因,目标参与者还处理创建 ThreadActor,用于在调试器中管理断点。

目标范围参与者期望在目标参与者上找到以下属性

  • threadActor:给定目标的 ThreadActor 实例,仅在调用 attach 请求时或在构造时定义。

  • isRootActor:(历史名称)始终为 false,除非在 ParentProcessTargetActor 上。尽管属性名称如此,但它被用于接受所有资源(例如 chrome 资源),而不是仅限于内容资源。

  • makeDebugger:用于为目标创建 Debugger 对象的辅助函数。(有关更多信息,请参阅 actors/utils/make-debugger.js)

除此之外,继承自 WindowGlobalTargetActor 的参与者公开了许多其他属性和事件

  • window:当前目标的窗口全局对象的引用。如果我们将目标切换到 iframe,它可能会随着时间的推移而改变,因此不应将其存储在变量中,而应始终从参与者中获取。

  • windows:所有文档全局对象(包括主窗口对象和所有 iframe)的列表。

  • docShell:目标文档的主要 docShell 引用。

  • docShells:目标文档及其所有 iframe 的所有 docShell 的列表。

  • chromeEventHandler:当前目标的 chrome 事件处理程序。允许监听可能在此文档本身中丢失/取消的事件。

有关更多详细信息,请参阅 WindowGlobalTargetActor 文档。

目标范围参与者 (Target-scoped actors)

这些参与者中的每一个都专注于提供一个特定的功能集。它们是给定目标参与者的子参与者。

它们返回的数据经过过滤以反映目标。例如,您从 WindowGlobalTargetActor 获取的 InspectorActor 会为您提供有关目标上下文中标记和样式的信息。

这些参与者可以通过拥有自己的子参与者(如 LongStringActor、WalkerActor 等)来扩展此层次结构。

为了提高性能,目标范围参与者是延迟创建的。目标参与者列出了每个参与者的参与者 ID,但此时实际上并没有加载和实例化参与者模块。一旦服务器收到对给定目标范围参与者的第一个请求,就会及时实例化该特定参与者以服务该请求。

所有这些参与者的参与者 ID 可以从每个目标参与者的“表单”中获取。“表单”由观察者参与者通过 target-avaible-form RDP 数据包通知。