Deferred
jQuery Deferred とか言っていますがコアは全く jQuery に依存しないので (いい名前がおもいつかないから jQuery バインディングのほうのなまえでよんでる) http://svn.coderepos.org/share/lang/javascript/jquery-deferred/jquery-deferred.js の Deferred 関数と必要な関数をコピペしたら GM でもうごきます。setTimeout/clearTimeout にだけ依存してるのでその実装があるならどこでもうごくはず。
他の非同期なやつを Deferred 化するのは jQuery Deferred だと
function wait (n) {
var d = new Deferred(), t = new Date();
var id = setTimeout(function () {
clearTimeout(id);
d.call((new Date).getTime() - t.getTime());
}, n * 1000)
d.canceller = function () { try { clearTimeout(id) } catch (e) {} };
return d;
}こんな感じになってます。Deferred#call がコールバック起動で、Deferred#fail がエラーバック起動です。
MochiKit のコードだと (機能がちょっと違いますが)
/** @id MochiKit.Async.wait */
wait: function (seconds, /* optional */value) {
var d = new MochiKit.Async.Deferred();
var m = MochiKit.Base;
if (typeof(value) != 'undefined') {
d.addCallback(function () { return value; });
}
var timeout = setTimeout(
m.bind("callback", d),
Math.floor(seconds * 1000));
d.canceller = function () {
try {
clearTimeout(timeout);
} catch (e) {
// pass
}
};
return d;
},引数 (value) をわたすためにチェインつかってるのがおもしろいすね。
ついでに jAutoPagerize でつかっているやつ。
function CachedResource (uri, convertfun, expire) {
var d = Deferred(); // new なしでいける。
var key = uri;
var v = {};
try { v = eval(GM_getValue(key)) || ({}) } catch (e) { log("parse error: may be uneval bug") }
d.clear = function () {
GM_setValue(key, "");
return this;
};
if (v.time && v.time > (new Date).getTime() - expire) {
log("Cache Hitted: " + key);
setTimeout(function () { d.call(v.body); }, 10);
} else {
log("Cache expired; getting... " + key);
GM_xmlhttpRequest({
method : "GET",
url : uri,
onload : function (req) { try {
var res = convertfun(req.responseText);
GM_setValue(key, uneval({time:(new Date).getTime(), body:res}));
log(key, uneval({time:(new Date).getTime(), body:res}));
log("Cached: " + key);
d.call(res);
} catch (e) { d.fail(e) } },
onerror : function (e) {
d.fail("HTTPError:"+e);
}
});
}
return d;
}