MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

Archive of obsolete content

在 extensions 中使用 workers

这篇文章为你演示了如何在不阻塞UI的情况下,利用worker进程在扩展中执行后台任务。

如果你还没创建一个扩展,或者想缕下自己的记忆,那么就看下这个系列中之前的文章。

下载样例

你可以从下面的链接下载完整的样例:

该版本和之前版本的区别

这个版本的stock ticker extension 将 获取最新股票信息的XMLHttpRequest调用移到了一个 worker thread,然后将那些信息传递到这个扩展代码的主体中,从而更新状态栏的展示。 这不仅展示了如何在扩展中使用workers,也展示了如何在worker中执行 XMLHttpRequest ,并且展示了workers和主线程之间如何来回传递数据。 

The worker

这个示例中worker thread的作用就是为了发出XMLHttpRequest的调用,从而获取最新的股票信息。 它所做的就是下面的内容: 每隔十分钟,它调用XMLHttpRequest,当接收到结果时,将含有接收到的数据的事件传递到主线程。

因此我们需要将 refreshInformation() 方法从 stockwatcher2.js文件中移动到ticker_worker.js中,这个文件将host the worker thread。 ticker_worker.js代码如下所示:

var symbol = "";

function refreshInformation() {
  if (!symbol) {
    throw "No symbol set!";
  }

  var fullUrl =
    "http://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();
}

当 worker thread被启动后, 代码主体 (在26-35行)被执行。通过设置一个间断的handler来开始它,这个handler每10分钟调用下refreshInformation() 。

然后它将这个worker的onmessage event handler 设置给接收event参数的一个函数, 并且做下面两件事中的一个:

  • 如果event里面含有数据区,正在被跟踪的stock symbol 就被设置成大写字母形式。这主要被用来初始化worker,并且改变正在被监视的股票。
  • 如果没有数据区,将调用refreshInformation() 方法来获取股票的最新信息,并回传到主线程中。这将为主线程提供一种开始明确请求worker的方式,从而立刻更新股票信息。

refreshInformation() 方法和之前的版本相当相似,也有两个需要注意的例外:

  • 如果股票代号没有被设置的话,将会抛出一个异常(4-6行)。
  • 当从XMLHttpRequest获取到结果时,并没有立刻更新状态栏的显示信息,而是通过worker的postMessage()方法向主线程发送一个消息。这是因为只有主线程才被允许更新UI。

主线程

这里的改动也相对较少,但是很重要。

startup() 方法

当扩展被加载的时候,这个方法就被调用了,并且需要更新下从而启动和配置worker。让我门看下代码:

  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);
  },

worker 在第13-22行被设置和配置:

  • 第13行实例化一个新的worker,明确ticker_worker.js文件的URI。
  • 第17-20行改变了worker的onmessage handler的定义,从而当worker回调到主线程的时候,主线程的this值是主线程的对象的,而不是worker的。
  • 第22行向ticker线程发送一个消息,从而告诉它监视什么代号。

observe() 方法

这个方法主要用来当用户更改首选项的时候,更新哪个股票正在被监视。它需要向worker发送一个消息,从而告诉它需要监视哪个股票代号。

  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;
    }
  },

第10行是关键, 通过调用ticker线程的postMessage()方法向监视器发送一个新的股票代码。

watchStock() and refreshInformation() 方法

这两个方法非常简单. watchStock()用来向ticker 线程传递代号; refreshInformation()的主要函数体现在在worker里面 ,被用来向worker简单传递一个空消息,从而告诉worker立刻刷新股票信息。

  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("");
  },

onworkermessage() 方法

当worker向主线程回传一个消息的时候,这个方法被调用。它主要用来向当前展示的状态栏中更新股票信息,在鼠标放到ticker上时,它也被用来更新显示的提示信息。这些代码基本和上个版本的做法一致,除了它是在事件中的response中完成的,而不是在refreshInformation() 方法中。

A note about ChromeWorkers

Requires Gecko 2.0(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

Gecko 2.0 添加了新的 ChromeWorker 对象, 提供了一个只能在chrome的应用和扩展中使用的worker。这个worker对象可以访问  js-ctypes, 而标准的worker是不能的。

See also

文档标签和贡献者

标签: 
 此页面的贡献者: wukuili, arya0822
 最后编辑者: wukuili,