愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

JSONPのエラーハンドリング(この記事の内容は結果としてエイプリルフールになりました)

※めんどくさい && アホの証拠として残しておくため 消しませんが、ここに書いた方法だと200以外の404とかに対応できないです。つまりダメです


http://d.hatena.ne.jp/NeoCat/20110206/1296934235

これって結局、根本的には

  • JSONPにおいては、200であっても「JavaScriptとして評価できない文字列が返ってきた場合」「こっち側で指定したコールバック関数(callbackA)の呼び出しがちゃんと行われなかった場合」にはエラー扱いにしたい
  • そのためには、script elementでloadされるJavaScript の評価が成功した場合でも失敗した場合でも必ず呼ばれるコールバック関数(callbackB)が必要だ
  • 実行順はcallbackA -> callbackBとなる必要がある(でないとJSONPの実行結果がとれない)

という要件があった上で、

  • script elementのonloadとonerrorはクロスブラウザ的な意味で信用できない
  • なので、iframeをかませてそのonloadをcallbackBとして使おう
  • callbackAの呼び出しが正しく行われた否かは、引数をまるっと変数に代入しておいて判定しよう

というロジックに至ったお話だと思うのだが、それだけなら別にiframeかます必要はなくて、callbackBとしてonloadが走るブラウザではonload、IEではonreadystatechangeを使って

var xds = {
    load: function(url, onsuccess, onerror, callbackKey) {
        callbackKey = callbackKey || "callback";

        var script = document.createElement("script");

        script.onload = script.onreadystatechange = function() {
            if ( this.readyState && this.readyState !== "loaded" ) return;

            if (xds.result) {
                if (onsuccess) onsuccess.apply(this, xds.result);
            }
            else if (onerror) {
                onerror();
            }

            script.parentNode.removeChild(script);
        };
        script.src = url + (url.indexOf("?") === -1 ? "?" : "&" ) + callbackKey + "=xds.callback";

        document.getElementsByTagName("head")[0].appendChild(script);
    },
    callback: function() {
        xds.result = arguments;
    }
};

こういうコードでも元々の要件は満たしている気がする。

または、僕が何か見落としているのかもしれない。

  • > よく考えたらこれだと200以外の時ダメでした。