The message manager

  • Revision slug: The_message_manager
  • Revision title: The message manager
  • Revision id: 57779
  • Created:
  • Creator: jdm
  • Is current revision? No
  • Comment 2 words added

Revision Content

{{ gecko_minversion_header("2.0") }}

The message manager is a message-passing framework for chrome script to touch content. In Firefox 4, chrome script can access content and content docshells directly through properties on a XUL {{ XULElem("browser") }} element. But in Mobile Firefox 4 and in a future version of Firefox, content will run in separate processes from chrome, and direct access will not be possible. Instead, chrome script must use separate scripts for code which must synchronously touch content, and run these scripts asynchronously using the message manager. The message manager is available in Firefox 4 so that Firefox code and extensions can start using the new API immediately, even before Firefox switches to use content processes.

Note: The message manager is a JavaScript-only API and will not be made available to binary components.

Messages

Messages passed through the message manager have a name and optional data. Sending a message is simple:

manager.sendAsyncMessage("message-name", {"foo": 2});

The data is serialized in the message. This means that it is not possible to send object references via messages. In other words, you can send over JSON data, which is serialized into a string (just like JSON.stringify) and parsed on the other side (just like JSON.parse).

When a message is sent from chrome to content, it must be dispatched asynchronously, because chrome is not allowed to block on content. However, content scripts may synchronously send a message to chrome and wait for a response:

var response = sendSyncMessage("message-name", {"foo": 1});

The response is an array of returned values from each listener.

Message listeners

Script can add message listeners to a message manager:

function listenerFunction(obj)
{
  ...
}

manager.addMessageListener("message name", listenerFunction);
manager.removeMessageListener("message name", listenerFunction);

Message properties

The listener function is called back with an object as its first parameter which contains the following properties:

  • name: [string] the name of the message
  • sync: [boolean] indicates if this message was sent as a synchronous or asynchronous message by the sender (only content can send synchronous messages to the parent)
  • json: [object] the JSON object with the data included by the sender
  • target: [XULElement] the {{ XULElem("browser") }} element associated with the content that this message came from
/* in the content script */
sendAsyncMessage("example", {title: document.title});

--------------------------

/* in the parent */
function listenerFunction(obj)
{
  var title = obj.json.title; // the title of the page
  var browser = obj.target;   // the browser associated with the page
  var name = obj.name;        // "example"
  var sync = obj.sync;        // false - sendAsyncMessage was used
}

browser.messageManager

There is one message manager per XUL {{ XULElem("browser") }} element. To get the message manager for the browser, simply use browser.messageManager.

window.messageManager

There is also a special window.messageManager which allows a chrome window to receive messages from any <browser> loaded in the window. Messages are sent to the <browser>.messageManager first, and then to the window.messageManager. Note that you cannot send messages to the window messageManager, you can only register to receive messages. When a message is received from a content process, listeners in the browser.messageManager are called first, followed by the ones in the window's message manager. If multiple message manager are listening for a synchronous message, all return values are sent back to the content script as an array. (ex. ["rv1 from browser.messageManager", "rv2 from browser.messageManager", "rv1 from window.messageManager", "rv2 from window.messageManager"])

Content scripts

In order for messages to be useful, a content script must be installed which either sends or receives messages and interacts with the DOM loaded into the browser. Before loading any pages into a <browser>, code running in the Chrome process uses browser.messageManager.loadFrameScript() to inject a script into the content process. That script then can add listeners into the content process and send result messages back to the chrome process.

Content scripts have the following globals:

  • content - The DOM window of the content loaded in the browser.
  • docShell - The nsIDocShell associated with the browser.
  • addMessageListener
  • removeMessageListener
  • sendAsyncMessage
  • sendSyncMessage
  • dump
  • atob
  • btoa

Content scripts access to everything that goes with content (docshells). They don't have access to the chrome UI directly.

A simple example

This simple example forwards all clicks on HTML {{ HTMLElement("a") }} elements to chrome. This is a simplified example, and won't work for child elements, but it should help understand how the messaging system works.

The content script

This code runs in the content process to set up an event listener that forwards the click events to the chrome process.

addEventListener("click",
  function(e) {
    if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement &&
        sendSyncMessage("linkclick", { href : e.target.href })[0].cancel) {
      e.preventDefault();
    }
  },
  false);

The chrome script

This code runs in chrome to receive the click events and load the content script.

browser.messageManager.addMessageListener("linkclick",
  function(m) {
    return { cancel: !confirm("Do you want to load " + m.json.href) };
  }
);
browser.messageManager.loadFrameScript("chrome://myextension/content/checklinks.js", true);

See also

{{ languages( { "ja": "ja/The_message_manager"} ) }}

Revision Source

<p>{{ gecko_minversion_header("2.0") }}</p>
<p>The message manager is a message-passing framework for chrome script to touch content. In Firefox 4, chrome script can access content and content docshells directly through properties on a XUL {{ XULElem("browser") }} element. But in Mobile Firefox 4 and in a future version of Firefox, content will run in separate processes from chrome, and direct access will not be possible. Instead, chrome script must use separate scripts for code which must synchronously touch content, and run these scripts asynchronously using the message manager. The message manager is available in Firefox 4 so that Firefox code and extensions can start using the new API immediately, even before Firefox switches to use content processes.</p>
<div class="note"><strong>Note:</strong> The message manager is a JavaScript-only API and will not be made available to binary components.</div>
<h2>Messages</h2>
<p>Messages passed through the message manager have a name and optional data. Sending a message is simple:</p>
<pre class="brush: js">manager.sendAsyncMessage("message-name", {"foo": 2});
</pre>
<p>The data is serialized in the message. This means that it is not possible to send object references via messages. In other words, you can send over JSON data, which is serialized into a string (just like JSON.stringify) and parsed on the other side (just like JSON.parse).</p>
<p>When a message is sent from chrome to content, it must be dispatched asynchronously, because chrome is not allowed to block on content. However, content scripts may synchronously send a message to chrome and wait for a response:</p>
<pre class="brush: js">var response = sendSyncMessage("message-name", {"foo": 1});
</pre>
<p>The response is an array of returned values from each listener.</p>
<h2>Message listeners</h2>
<p>Script can add message listeners to a message manager:</p>
<pre class="brush: js">function listenerFunction(obj)
{
  ...
}

manager.addMessageListener("message name", listenerFunction);
manager.removeMessageListener("message name", listenerFunction);
</pre>
<h2>Message properties</h2>
<p>The listener function is called back with an object as its first parameter which contains the following properties:</p>
<ul> <li>name: [string] the name of the message</li> <li>sync: [boolean] indicates if this message was sent as a synchronous or asynchronous message by the sender (only content can send synchronous messages to the parent)</li> <li>json: [object] the JSON object with the data included by the sender</li> <li>target: [XULElement] the {{ XULElem("browser") }} element associated with the content that this message came from</li>
</ul>
<pre class="deki-transform">/* in the content script */
sendAsyncMessage("example", {title: document.title});

--------------------------

/* in the parent */
function listenerFunction(obj)
{
  var title = obj.json.title; // the title of the page
  var browser = obj.target;   // the browser associated with the page
  var name = obj.name;        // "example"
  var sync = obj.sync;        // false - sendAsyncMessage was used
}
</pre>
<h2>browser.messageManager</h2>
<p>There is one message manager per XUL {{ XULElem("browser") }} element. To get the message manager for the browser, simply use <code>browser.messageManager</code>.</p>
<h2>window.messageManager</h2>
<p>There is also a special window.messageManager which allows a chrome window to receive messages from any &lt;browser&gt; loaded in the window. Messages are sent to the &lt;browser&gt;.messageManager first, and then to the window.messageManager. Note that you cannot <em>send </em>messages to the window messageManager, you can only register to receive messages. When a message is received from a content process, listeners in the browser.messageManager are called first, followed by the ones in the window's message manager. If multiple message manager are listening for a synchronous message, all return values are sent back to the content script as an array. (ex. ["rv1 from browser.messageManager", "rv2 from browser.messageManager", "rv1 from window.messageManager", "rv2 from window.messageManager"])</p>
<h2>Content scripts</h2>
<p>In order for messages to be useful, a content script must be installed which either sends or receives messages and interacts with the DOM loaded into the browser. Before loading any pages into a &lt;browser&gt;, code running in the Chrome process uses browser.messageManager.loadFrameScript() to inject a script into the content process. That script then can add listeners into the content process and send result messages back to the chrome process.</p>
<p>Content scripts have the following globals:</p>
<ul> <li>content - The DOM window of the content loaded in the browser.</li> <li>docShell - The nsIDocShell associated with the browser.</li> <li>addMessageListener</li> <li>removeMessageListener</li> <li>sendAsyncMessage</li> <li>sendSyncMessage</li> <li>dump</li> <li>atob</li> <li>btoa</li>
</ul>
<p>Content scripts access to everything that goes with content (docshells). They don't have access to the chrome UI directly.</p>
<h2>A simple example</h2>
<p>This simple example forwards all clicks on HTML {{ HTMLElement("a") }} elements to chrome. This is a simplified example, and won't work for child elements, but it should help understand how the messaging system works.</p>
<h3>The content script</h3>
<p>This code runs in the content process to set up an event listener that forwards the click events to the chrome process.</p>
<pre class="brush: js">addEventListener("click",
  function(e) {
    if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement &amp;&amp;
        sendSyncMessage("linkclick", { href : e.target.href })[0].cancel) {
      e.preventDefault();
    }
  },
  false);</pre>
<h3>The chrome script</h3>
<p>This code runs in chrome to receive the click events and load the content script.</p>
<pre class="brush: js">browser.messageManager.addMessageListener("linkclick",
  function(m) {
    return { cancel: !confirm("Do you want to load " + m.json.href) };
  }
);
browser.messageManager.loadFrameScript("chrome://myextension/content/checklinks.js", true);
</pre>
<h2>See also</h2>
<ul> <li><a class=" link-https" href="https://wiki.mozilla.org/Content_Process_Event_Handlers" title="https://wiki.mozilla.org/Content_Process_Event_Handlers">Content Process Event Handlers</a> (design document)</li>
</ul>
<p>{{ languages( { "ja": "ja/The_message_manager"} ) }}</p>
Revert to this revision