Greasemonkey 複数のGM_xmlhttpRequestを同期取りながら順番に呼び出す
Greasemonkey の GM_xmlhttpRequest で外部サイトのデータを取得するとき。 Aのページを取得して、その内容を元にBのページにリクエストをかけたいときに、普通に onload に書いていくとネストが深くなっていって、何がなんだかわからなくなってしまう。
ソースをちょっとキレイにするためにこんなの作ってみました。
先に使い方から
//
// 使い方の例
//
// チェーンオブジェクトを作る
var chain = new Chain();
// 「addRequestFunction」で他サイトと通信するジョブを追加
// 引数は、GM_xmlhttpRequest の引数に渡すデータを返す関数。ややこしい><
chain.addRequestFunction( function() { return {
method: 'GET',
url: 'http://twitter.com/statuses/public_timeline.json',
onload: function( response ) {
// this = chain
this.public_timeline = eval( "(" + response.responseText + ")" );
}
}});
// 「addFunction」で普通の関数を追加
chain.addFunction( function() {
// ここでは既に public_timeline にデータがセットされてる。便利!
// this 経由でアクセスできるよ。
var div = document.createElement( "div" );
var txt = document.createTextNode( this.public_timeline[0].user.name );
div.appendChild( txt );
document.body.appendChild( div );
});
// 先頭にいた人のユーザー情報を取得してみよう。
chain.addRequestFunction( function() {
// ここからも this でアクセスできるよ
var id = this.public_timeline[0].user.screen_name;
// 先頭にいた人のユーザー情報を取得するジョブ
return {
method: 'GET',
url: "http://twitter.com/users/show/" + id + ".json",
onload: function( response ) {
this.user = eval( "(" + response.responseText + ")" ); // this = chain
}
}
});
chain.addFunction( function() {
var img = document.createElement( "img" );
img.src = this.user.profile_image_url; // this = chain
document.body.appendChild( img );
});
// 「doChain」で追加してきた関数を次々と実行する。
chain.doChain();
ソース
//
// チェーンを順番に実行して行くクラス。
//
function Chain() {
// コンストラクタ
this.jobs = [];
this.container = {};
// チェーンに GM_xmlhttpRequest の引数を返す関数を追加する。
this.addRequestFunction = function( f ) {
this.jobs.push({ type: 'request', func: f })
};
// チェーンに普通の関数を追加する。
this.addFunction = function( f ) {
this.jobs.push({ type: 'function', func: f })
};
// 先頭のジョブを返す
this.shift = function() {
return this.jobs.shift();
};
// チェーンを順番に実行して行く。
this.doChain = function () {
// 先頭のジョブを取り出す。何もなかったらおしまい。
var job = this.jobs.shift();
if( ! job ) return;
if( job.type == 'function' ) {
// 関数ならそのまま実行する。
job.func.apply( this );
this.doChain();
} else if( job.type == 'request' ) {
// objectだったら非同期通信。ちょっといじってから実行する。
var obj = job.func.apply( this );
obj.chain = this;
if( obj.onload ) {
obj.$onload = obj.onload;
obj.onload = function( response ) {
obj.$onload.apply( this.chain, [response] );
this.chain.doChain();
}
}
GM_xmlhttpRequest( obj );
}
};
}
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)