クロスドメインJavaScript呼び出しをクラス化, クロージャにも対応
以前twicli開発メモで、JavaScriptでJSONPを返すクロスドメイン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;