Home > Latest topics

Latest topics > xpcshellでタイマーやXMLHttpRequestなどの非同期処理を扱う方法(Gecko 1.9以降限定)

宣伝1。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

宣伝2。Firefox Hacks Rebooted発売中。本書の1/3を使って、再起動不要なアドオンの作り方のテクニックや非同期処理の効率のいい書き方などを解説しています。既刊のFirefox 3 Hacks拡張機能開発チュートリアルと併せてどうぞ。

Firefox Hacks Rebooted ―Mozillaテクノロジ徹底活用テクニック
浅井 智也 池田 譲治 小山田 昌史 五味渕 大賀 下田 洋志 寺田 真 松澤 太郎
オライリージャパン

xpcshellでタイマーやXMLHttpRequestなどの非同期処理を扱う方法(Gecko 1.9以降限定) - Feb 06, 2010

XPConnectも使えるコマンドラインのJavaScript実行環境で、xpcshellという物がある。XULRunnerをダウンロードするとおまけでついてくる。

  • 引数無しで実行すると対話インターフェースが起動する。irbみたいな感じで使える。
  • -fオプションを付けると外部のファイルをスクリプトとして実行できる。なので、JavaScriptでシェルスクリプトっぽいことができる。

xpcshell内ではWindowオブジェクトが無いので、当然だけどWindow.setTimeout()Window.setInterval()等を使った遅延処理は書けない。でもXPConnectは使えるので、nsITimerの機能を使えば似たようなことはできるはず。

という事で以下のようなスクリプトを書いて-fオプションで読み込ませてみたけど、実はこのままでは期待通りに動いてくれない。

var Cc = Components.classes;
var Ci = Components.interfaces;

function Timeout(aCallback, aDelay) {
  this.finished = false;
  this.callback = aCallback;
  this.init(aDelay);
}
Timeout.prototype = {
  init : function(aDelay) {
    this.timer = Cc['@mozilla.org/timer;1']
                  .createInstance(Ci.nsITimer);
    this.timer.init(this, aDelay, Ci.nsITimer.TYPE_ONE_SHOT);
  },
  cancel : function() {
    if (!this.timer) return;
    delete this.timer;
    delete this.callback;
    this.finished = true;
  },
  observe : function(aSubject, aTopic, aData) {
    if (aTopic != 'timer-callback') return;

    if (typeof this.callback == 'function')
      this.callback();
    else
      eval(this.callback);

    this.cancel();
  }
};

print('START');

var timeout = new Timeout(
    function() {
      print('3 SEC AFTER');
    },
    3000
  );

これを実行しても、「START」と出てすぐに終わってしまう。何故かというと、xpcshellはメインスレッドの処理が終わったらその時点でxpcshell自体を終了させてしまうからなのだそうだ。

UxU 0.7.6でも使ってるGecko 1.9以降のスレッド関係の機能を使うと、この問題を解消できる。さっきのスクリプトの末尾に以下を加えて実行すると、今度は「START」と出た3秒後に「3 SEC AFTER」「END」と出てからxpcshellが終了するようになる。

var thread = Cc['@mozilla.org/thread-manager;1']
              .getService()
              .mainThread;
while (!timeout.finished) {
  thread.processNextEvent(true);
}

print('END');

多分nsITimerのタイマー機能以外でも、これ(フラグが立つまでwhileでループ回してメインスレッドを止める)でうまくいくんじゃないかと思う。

XMLHttpRequestも試してみた。

var Cc = Components.classes;
var Ci = Components.interfaces;

var request = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
                .createInstance(Ci.nsIXMLHttpRequest)
                .QueryInterface(Ci.nsIDOMEventTarget);

var loaded = false;
request.open('GET', 'http://piro.sakura.ne.jp/', true);
request.addEventListener('load', function() {
  print(request.responseText);
  loaded = true;
}, false);
request.send(null);

print('REQUESTING...');

var thread = Cc['@mozilla.org/thread-manager;1']
              .getService()
              .mainThread;
while (!loaded) {
  thread.processNextEvent(true);
}

print('END');

これも、ちゃんとレスポンスが帰ってきてから終了した。

分類:Mozilla > XUL, , , , , 時刻:22:46 | Comments/Trackbacks (0) | Edit

Comments/Trackbacks

TrackBack ping me at


の末尾に2014年1月19日時点の日本の首相のファミリーネーム(ローマ字で回答)を繋げて下さい。例えば「noda」なら、「2010-02-06_xpcshell-delayed.trackbacknoda」です。これは機械的なトラックバックスパムを防止するための措置です。

Post a comment

writeback message: Ready to post a comment.

2014年1月19日時点の日本の首相のファミリーネーム(ひらがなで回答)

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

Mozilla Firefox ブラウザ無料ダウンロード