MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

消息管理器概述

这篇翻译不完整。请帮忙从英语翻译这篇文章

在多进程 Firefox 中有两个进程:

  • chrome 进程,也称父进程,运行着浏览器 UI 界面 (chrome) 的代码和扩展安装的代码。
  • 内容进程,也称子进程,运行着所有网页内容。在未来的 Firefox 版本中,不同的标签页可能运行在不同的进程中,但截至目前,所有内容标签页共享使用同一个内容进程。

消息管理器的设计目的是使运行在一个进程中的 chrome 特权的 JavaScript 代码能够与不同进程中的 chrome 特权的 JavaScript 代码通信。

本文介绍了几种类型的消息管理器,如何访问它们,以及在一个较高层面你可以使用什么。

在顶层,有两种不同类型的消息管理器:

  • 框架消息管理器:这些使 chrome 进程的代码能够加载脚本到内容进程中的浏览器框架(基本上,就是指一个浏览器标签页)。这些脚本被称为框架脚本,顾名思义,它们限定在特定的浏览器框架中。如果 chrome 代码想要在内容进程中运行可以方便访问网页内容的代码,通常就是使用消息管理器的时候了。
  • 进程消息管理器:这些对应着进程边界,使运行在父 (chrome) 进程中的代码能够与子 (内容) 进程中的代码通信。从 Firefox 38 起,这也使运行在父进程中的代码能够加载进程脚本到子进程。这些类似框架脚本,除了它们是全局访问子进程。进程脚本最有用的时候是进程想要只在内容进程中运行某些代码,来访问某些全局服务:例如,注册一个 observer 或者一个 内容策略

框架消息管理器

在多进程 Firefox 中,当 chrome 代码需要与网页内容交互时,它需要:

  • 将需要直接访问内容的脚本代码放到一个单独的脚本,它被称为“框架脚本”。
  • 使用框架消息管理器来加载这些框架脚本到内容进程
  • 使用框架消息管理器 API 来与框架脚本通信

Some older articles on multiprocess Firefox and the message manager might refer to "content scripts" instead of "frame scripts", but this usage is deprecated because the Add-on SDK uses "content script" to refer to a similar but different kind of script.

因此从根本上,框架消息管理器使 chrome 代码能够:

  • 加载一个脚本到一个内容进程中的框架(基本上,就是指一个浏览器标签页)。这些脚本被称为“框架脚本”。
  • 使用消息传递 API 与框架脚本通信

有多种类型的框架消息管理器,如图所示:

This diagram shows the setup when there are 2 browser windows open, one with 2 tabs open and one with 1 tab open.

Chrome 进程

In the chrome process, there's a hierarchy of frame message managers: the global frame message manager, window message managers, and browser message managers.

全局框架消息管理器

Description

There's a single global frame message manager in the chrome process.

This operates on all frames, in all content tabs. If you load a frame script using the global frame message manager, the script gets loaded separately into every open tab: three times, in the diagram above. Similarly, if you send a message using the global frame message manager, it's received by all content tabs, and is then delivered to any frame scripts that are listening for it.

Its most important functions and attributes are:

childCount : contains the number of children (typically, browser windows)

getChildAt() : get the child at the given index

loadFrameScript() : load a frame script into every tab in the browser

broadcastAsyncMessage() : send a message to frame scripts

addMessageListener() : start listening to a specific message from all frame scripts

removeMessageListener() : stop listening to a specific message

Interfaces

nsIFrameScriptLoader

nsIMessageListenerManager

nsIMessageBroadcaster

How to access

Access it using Components.classes:

// chrome script
let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
  .getService(Ci.nsIMessageListenerManager);

窗口消息管理器

Description

There's a window message manager for every browser window: two, in the diagram above.

It operates on all content tabs in a given window. If you load a frame script using the window message manager it gets loaded separately into each tab open in that particular window. If you send a message using the window message manager, it gets sent to all content tabs in that window.

Its most important functions and attributes are:

childCount : contains the number of children (typically, browser tabs)

getChildAt() : get the child at the given index

loadFrameScript() : load a frame script into every tab in this window

broadcastAsyncMessage() : send a message to all frame scripts in this window

addMessageListener() : start listening to a specific message from frame scripts

removeMessageListener() : stop listening to a specific message

Interfaces

nsIFrameScriptLoader

nsIMessageListenerManager

nsIMessageBroadcaster

How to access

You can access it as a property of the browser window:

// chrome script
let windowMM = window.messageManager;

浏览器消息管理器

Note that in this context, "browser" refers to the XUL <browser> object, which is a frame that hosts a single Web document. It does not refer to the more general sense of a Web browser.

Description

Finally, there's a browser message manager for every open content tab: three, in the diagram above.

This corresponds one-to-one with a content tab. Scripts you load using a browser message manager are loaded only into that content tab, and messages you send are delivered only to that content tab.

You can mix and match: so for example, you could load a script into every tab using the global message manager, but then send a message to the script instance loaded into a specific tab by using the browser message manager.

Its most important functions are:

loadFrameScript() : load a frame script into this browser frame (tab)

sendAsyncMessage() : send a message to all frame scripts in this browser frame

addMessageListener() : start listening to a specific message from frame scripts

removeMessageListener() : stop listening to a specific message

Interfaces

nsIProcessChecker

nsIFrameScriptLoader

nsIMessageListenerManager

nsIMessageSender

How to access

The browser message manager can be accessed as a property of the XUL <browser> element:

// chrome script
let browserMM = gBrowser.selectedBrowser.messageManager;

内容进程

内容框架消息管理器

Description

There's a content frame message manager for every open tab. It's the content-side end of frame message manager conversations.

Frame scripts are loaded into the content frame message manager scope, and messages from chrome message managers end up here.

The content frame message manager provides the global object for frame scripts (but note that there is trickery to ensure that top-level variables defined by frame scripts are not shared).

Frame scripts can use this object to send messages to the chrome process, and to receive messages from the chrome process.

Its most important attributes and functions are:

content : access the DOM window hosted by the tab

docShell : access the top-level docshell

Components : access privileged objects and APIs

addEventListener() : listen to DOM events

addMessageListener() : receive messages from the chrome process

sendAsyncMessage() : send asynchronous messages to the chrome process

sendSyncMessage() : send synchronous messages to the chrome process

Interfaces

nsIDOMEventTarget

nsIMessageListenerManager

nsIMessageSender

nsISyncMessageSender

nsIContentFrameMessageManager

How to access The content frame message manager is the global object in frame scripts.

进程消息管理器

Process message managers correspond to process boundaries, and enable code running in different processes to communicate. Multiprocess Firefox has the concept of:

  • a "parent process"
  • "child processes" which are processes spawned by the parent process.

For practical purposes, in multiprocess Firefox the parent process is the chrome process, and child processes are content processes. 

In each child process, there's a single child process message manager (CPMM). There's also an additional child-in-process message manager (CIPMM) in the parent process.

For each child process message manager, there's a parent process message manager (PPMM) in the parent process.

There's also a single global parent process message manager (GPPMM) in the parent process, that provides access to all the parent process message managers. The diagram below shows the setup that would result from having two child processes:

With the GPPMM, you can broadcast messages to the CIPMM and all CPMMs. With a PPMM, you can send a message to its corresponding CPMM. With a CPMM, you can send messages to the parent process: these messages are received first by the corresponding PPMM, then by the GPPMM.

From Firefox 38 onwards, you can also use a parent process message manager to load a script into a child process. This is the recommended way to load a script that executes just once per child process, which is something you might want to do if you are interacting with some global service (for example, adding listeners to observer notifications or registering a content policy).

父消息管理器

全局父进程消息管理器

Description

The global parent process message manager (GPPMM) is global to the parent process.

  • Messages sent using the GPPMM get sent to all CPMMs in all child processes.
  • Process scripts loaded using the GPPMM get loaded in all child processes.

Its most important functions and attributes are:

childCount : contains the number of children (child processes, plus the in-content child)

getChildAt() : get the child at the given index

loadProcessScript() : load a process script into every content process

broadcastAsyncMessage() : send a message to all process scripts

addMessageListener() : start listening to a specific message from process scripts

removeMessageListener() : stop listening to a specific message

Interfaces

nsIProcessScriptLoader

nsIMessageListenerManager

nsIMessageBroadcaster

How to access

You can access the GPPMM with code like this:

// parent process
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
           .getService(Ci.nsIMessageBroadcaster);

You can also access it as the ppmm property of Services.jsm, if you are in the parent process.

父进程消息管理器

Description

There's one parent process message manager (PPMM) in the parent process for every child process, and its API is oriented to that one child process.

  • Messages sent using the PPMM are received only by the corresponding CPMM
  • Scripts loaded using the PPMM are loaded only into the corresponding child process.

Its most important functions are:

loadProcessScript() : load a process script into the content process

broadcastAsyncMessage() : send a message to process scripts

addMessageListener() : start listening to a specific message from process scripts

removeMessageListener() : stop listening to a specific message

Interfaces

nsIProcessChecker

nsIProcessScriptLoader

nsIMessageListenerManager

nsIMessageSender

How to access

You can access a PPMM using the getChildAt() function in the GPPMM:

// parent process
let ppmm = Services.ppmm.getChildAt(1);

子进程

子进程消息管理器

Description

There's one child process message manager (CPMM) in each child process. Messages sent using the CPMM are sent to the corresponding PPMM and are also relayed to the GPPMM.

Its most important attributes and functions are:

Components : access privileged objects and APIs

addMessageListener() : receive messages from the parent process

sendAsyncMessage() : send asynchronous messages to the parent process

sendSyncMessage() : send synchronous messages to the parent process

Interfaces

nsIMessageListenerManager

nsIMessageSender

nsISyncMessageSender

nsIContentProcessMessageManager

How to access

Code running in a child process can access the CPMM with code like this:

// child process script
let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
           .getService(Ci.nsISyncMessageSender);

You can also access it as the cpmm property of Services.jsm, if you are in the child process.

文档标签和贡献者

 此页面的贡献者: yfdyh000
 最后编辑者: yfdyh000,