这篇翻译不完整。请帮忙从英语翻译这篇文章。
This article shows you how to use worker threads in extensions to perform tasks in the background without blocking the user interface.
If you haven't already created an extension, or would like to refresh your memory, take a look at the previous articles in this series:
- Creating a status bar extension
- Creating a dynamic status bar extension
- Adding preferences to an extension
- Localizing an extension
- Updating an extension to support multiple Mozilla applications
Download the sample
You may download the complete example:
How this differs from previous versions
This version of the stock ticker extension moves the XMLHttpRequest
call that fetches updated stock information into a worker thread, which then passes that information back to the main body of the extension's code to update the display in the status bar. This demonstrates not only how to use workers in an extension, but also how to perform XMLHttpRequest
in a worker, and how workers and main thread code can pass data back and forth.
The worker
The worker thread's job in this example is to issue the XMLHttpRequest
calls that fetch the updated stock information. That's all it does. Every 10 minutes, it calls XMLHttpRequest
, and, when the results are received, sends an event back to the main thread with the received data.
So we need to move the refreshInformation()
method from the stockwatcher2.js
file into a separate file that will host the worker thread. That file, ticker_worker.js
, is shown here:
var symbol = ""; function refreshInformation() { if (!symbol) { throw "No symbol set!"; } var fullUrl = "https://quote.yahoo.com/d/quotes.csv?f=sl1d1t1c1ohgv&e=.csv&s=" + symbol; function infoReceived() { var output = httpRequest.responseText; if (output) { postMessage(output.trim()); } httpRequest = null; } var httpRequest = new XMLHttpRequest(); httpRequest.open("GET", fullUrl, true); httpRequest.onload = infoReceived; httpRequest.send(null); } setInterval(function() { refreshInformation(); }, 10*60*1000); onmessage = function(event) { if (event.data) { symbol = event.data.toUpperCase(); } refreshInformation(); }
When the worker thread is started, the main body of this code (in lines 26-35) is executed. It starts by setting up an interval handler (in lines 26-28) that calls refreshInformation()
every 10 minutes.
Then it sets the worker's onmessage
event handler to a function which looks at the event passed into it, and does one of two things:
- If there is a data field on the event, the stock symbol being tracked is set to the upper case version of that value. This is used to initialize the worker, and to change which stock is being monitored.
- If there is no data field, the
refreshInformation()
method is called to fetch the latest information about the stock and pass it back to the main thread. This provides a way for the main thread to specifically request that the worker update the stock information at once.
The refreshInformation()
method is fairly similar to the previous versions, with two notable exceptions:
- If the ticker symbol has not been set yet, an exception is thrown (lines 4-6).
- When the result is received from
XMLHttpRequest
, instead of immediately updating the displayed information in the status bar, a message is sent to the main thread using the worker'spostMessage()
method. This is because only the main thread is allowed to access the user interface.
The main thread
The changes here are also relatively minor, but crucial.
The startup() method
This method is called when the extension is first loaded, and needs to be updated to start up and configure the worker. Let's take a look:
startup: function() { // Register to receive notifications of preference changes this.prefs = Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefService) .getBranch("stockwatcher2."); this.prefs.QueryInterface(Components.interfaces.nsIPrefBranch2); this.prefs.addObserver("", this, false); this.tickerSymbol = this.prefs.getCharPref("symbol").toUpperCase(); this.worker = new Worker("chrome://stockwatcher2/content/ticker_worker.js"); // Small little dance to get 'this' to refer to StockWatcher, not the // worker, when a message is received. var self = this; this.worker.onmessage = function(event) { self.onworkermessage.call(self, event); }; this.worker.postMessage(this.tickerSymbol); },
The worker is set up and configured here in lines 13-22:
- Line 13 instantiates a new worker, specifying the URI of the
ticker_worker.js
file. - Lines 17-20 change the definition of the worker's
onmessage
handler so that when the worker calls back to the main thread, the main thread's value of this is correctly the main thread's object instead of the worker's. - Line 22 sends a message to the ticker thread to tell it what symbol to monitor.
The observe() method
This method's job is to update which stock is being monitored when the user changes the preferences. It needs to be updated to post a message to the worker to tell it which stock symbol to track.
observe: function(subject, topic, data) { if (topic != "nsPref:changed") { return; } switch(data) { case "symbol": this.tickerSymbol = this.prefs.getCharPref("symbol").toUpperCase(); this.worker.postMessage(this.tickerSymbol); break; } },
The key here is line 10, which sends the new ticker symbol to monitor to the ticker thread by calling its postMessage()
method. This results in the ticker's onmessage
handler being called.
The watchStock() and refreshInformation() methods
These two methods are very simple. watchStock()
is updated to pass the symbol to the ticker thread, and refreshInformation()
, whose main functionality is now in the worker, is updated to simply pass an empty message to the worker, which tells the worker to refresh the stock information immediately.
watchStock: function(newSymbol) { this.tickerSymbol = newSymbol.toUpperCase(); this.prefs.setCharPref("symbol", newSymbol); this.worker.postMessage(this.tickerSymbol); }, refreshInformation: function() { // Empty message just means 'refresh'. this.worker.postMessage(""); },
The onworkermessage() method
This method is called when the worker posts a message back to the main thread. Its job is to update the ticker information that's currently displayed in the status bar, as well as to update the tooltip that appears while the mouse cursor is hovering over the ticker. This code is essentially identical to what's done in the previous version, except that it's done in response to an event instead of within the refreshInformation()
method.
A note about ChromeWorkers
Requires Gecko 2.0(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)Gecko 2.0 added the new ChromeWorker
object, which provides a special chrome-only worker that can be used by applications and extensions. This worker object has access to js-ctypes, which standard workers do not have.