2011年 02月 16日

JSDeferred を Jetpack (Add-on SDK) で使う

binding を書いた (まだブランチに入れてある)

  • setTimeout/clearTimeout がないので nsITimer で実装 (これでいいのか?)
  • Deferred.postie という utility を追加

Deferred.postie(constructor, options) を使って widget/panel をつくるとメソッドが増えます。

  • post(args..., function) //=> Deferred
    • function をレシーバの content context 内で args と共に呼び、結果を取得
  • bind(selector, event, function) //=> Deferred
    • content 内の selector でマッチする要素全てで、 event が発火時 function (chrome context) を呼びだす

以下のように書けます。post に渡す関数は文字列化されて content に渡されるので、スコープを外部と共有していない。args も JSON で表現できるものしか渡せない。この点わかりにくいのでイマイチかもしれない。

完全に message のやりとりを置き換えられるわけではないけど、ちょっとしたイベント処理とかは直列で簡単に書けるようになるので、便利な場合は便利かもしれない。

const Deferred = require("jsdeferred").Deferred;
Deferred.define(this); //define 使う場合必ず引数に this を渡す必用あり

widget = Deferred.postie(widgets.Widget, {
	label      : "Foo",
	contentURL : 'http://example.com/',
	width      : 32,
	onClick    : function () {
		var self = this;

		next(function () {
			return self.
				post(1, 2, function (a, b) { // content context 
					return a + b;
				}).
				next(function (res) { // chrome context
					console.log(res);
				});
		}).
		next(function () {
			return wait(1);
		}).
		next(function () {
			return self.
				post(function (a, b) {
					throw "foo";
				}).
				next(function (res) {
					console.log(res);
				}).
				error(function (e) {
					console.log(e);
				});
		});
	},
	onMessage : function (message) {
		console.log(message);
	},
	contentScript : 'setTimeout(function () { postMessage("custom message") }, 1000)',
});

widget.post(function () {
	var d = new Deferred();
	setTimeout(function () {
		d.call(1);
	}, 1000);
	return d;
}).
next(function (a) {
	console.log("Hello! " + a);
}).
error(function (e) {
	console.log(e);
});

widget.bind("body", "click", function (e) {
	console.log("body clicked" + e);
}).
error(function (e) {
	console.log(e);
});