クロスドメインJavaScript呼び出しをクラス化, クロージャにも対応

以前twicli開発メモで、JavaScriptJSONPを返すクロスドメインAPIを動的に呼び出す方法を書きました。が、script要素を覚えておいて削除する必要があるetc. いろいろと面倒でした。そこでクラス化し、クロージャを使って自動的に不要なタグを除去するようにしました。さらにコールバックとして無名変数・クロージャを呼び出すことも可能ですので、できることが広がると思います。


ユーザ側ではこのエントリ末尾のクラスを読み込み、

function callbackFunc(arg) {
   // ...
}
xds.load("http://nekoneko/nyan?arg=myu", callbackFunc);

もしくはクロージャを使って

xds.load("http://twitter.com/account/rate_limit_status.json",
           function(ans){ for(x in ans) alert(x+":"+ans[x]) });

などと書いてあげればOKです。
xds.loadの第1引数は、JSONP形式で結果を返すAPIのURL(呼び出し時に自動的にcallback=〜が追加される)です。第2引数に指定したcallbackFuncという関数オブジェクトに結果が渡されます。


返り値としてIDが戻ります。結果が戻る前に、このIDを指定して xds.abort(id) を呼び出すと、スクリプトの実行をキャンセルできるはずです(動的なscript要素が非同期に実行されるブラウザのみ。Operaでは不可?)。


なおcallback=〜に入るのは毎回自動生成されるクロージャ名になります。従って、同じURLを複数回呼び出した場合の挙動が以前のバージョンと異なります。以前のものは結果がキャッシュされて実際にはAPIが呼び出されない場合がありましたが、今回は毎回発行されます。*1


以下、クラスの実装(xds変数の名前をクラス内で参照しているので注意)。

2008/9/4追記: 以前のスクリプトは複数引数を取れないバグがありました。以下は修正版です。
2010/2/6追記: エラー処理を追加したバージョンを別記事に書きました。: JSONPの動的取得+エラー処理 - Okiraku Programming
function XDomainScript() {
	this.cb_cnt = (new Date).getTime();
}
XDomainScript.prototype = {
    load: function(url, callback) {
        var id = this.cb_cnt++;
        var ele = document.createElement("script");
        ele.src = url + (url.indexOf('?') < 0 ? '?' : '&') + 'callback=xds.cb' + id;
        ele.type = "text/javascript";
        this['cbe' + id] = ele;
        this['cb' + id] = function(){ this.abort(id); callback.apply(this, arguments); }
        document.body.appendChild(ele);
        return id;
    },
    abort: function(id) {
        var ele = this['cbe' + id];
        ele.parentNode.removeChild(ele);
        delete this['cb' + id];
        delete this['cbe' + id];
    },
}
var xds = new XDomainScript;

*1:twicliではキャッシュを防ぐために小細工していましたので、これが不要になりました。