JSDeferred with jQuery


ある案件でjQueryのgetJSONメソッドを使っていてgetJSONメソッドでは使いづらい部分があった。
この問題をなんとか解決できないかと調べてみたらJSDeferred(cho45.stfuawsc.com)という面白いJavaScriptのライブラリを見つけた。

jQueryのgetJSONメソッドの使いづらい点

  • エラーハンドリングができない
    $.ajaxメソッドを使えばエラーハンドリングは可能であるが、読み込むデータがJSONの場合はgetJSONメソッドの方が簡潔にコードを記述できるのでgetJSONメソッドでエラーハンドリングができるようにしたい。

  • 複数のJSONデータが必要な場合に非同期で処理をおこなうにはgetJSONメソッドをネストさせる必要がある。

例えば以下のようなコードになる。

$.getJSON("foo.json").next(function (foo_data) {
    $.getJSON("bar.json").next(function (bar_data) {
        // ここでfoo.jsonとbar.jsonを処理するコードを記述する。
    });
});

JSDeferredは単独で使う事もできるがjQueryと組み合わせて使う事もでき、その場合にはgetJSONメソッドでエラーハンドルをおこなう事ができる。
また、非同期処理や並列処理もおこなう事ができる。

JSDeferred についての説明は本家のdoc/intro.html (Japanese)ページに載っているので、ここではおもにjQueryと組み合わせて使う場合について説明する。

JSDeferredをjQueryと組み合わせて使う場合はJSDeferredをダウンロードしてその中に含まれるjsdeferred.jquery.jsを読み込む必要がある。

通常はJSDeferredの関数を使う前に$.deferred.define()メソッドを呼び出してJSDeferredの関数をグローバル関数として公開する必要がある。

以下のリストは、JSDeferredの関数nextメソッドを呼び出した例である。
nextメソッドの引数として実行される関数は非同期で実行されるため、alert(1),alert(2)の順で実行される。

<script type="text/javascript" src="../js/jsdeferred.jquery.js"></script>
<script type="text/javascript">

    $.deferred.define();

    next(function () {
        alert(2);
    });
    alert(1);

</script>

グローバル関数として公開したくない場合は$.deferred.define()メソッドを使わずにDeferredクラスのクラスメソッドとしてJSDeferredの関数をを呼び出してやれば良い。
その場合は以下のリストのようになる。

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="../js/jsdeferred.jquery.js"></script>
<script type="text/javascript">

    Deferred.next(function () {
        alert(2);
    });
    alert(1);

</script>

また、jQueryを使わずに単独でJSDeferredを使う場合は以下のコードとなる。

<script type="text/javascript" src="../js/jsdeferred.js"></script>
<script type="text/javascript">

    Deferred.define();

    next(function () {
        alert(2);
    });
    alert(1);

</script>

next関数のもう少し複雑な例を紹介する。
以下の例はnext関数の引数である関数の中で更にnext関数を実行した例である。
alert(1)からalert(5)の順で実行される。

next(function () {
    next(function () {
        alert(4);
    }).next(function () {
        alert(5);
    });
    alert(2);
}).next(function () {
    alert(3);
});
alert(1);

wait関数を使って実行のタイミングを遅らせる事もできる。

wait関数の引数は秒単位で指定する。
elapsed引数にはミリ秒単位で実際の遅れ時間が返される。
ここでconsole.logメソッドはFireFoxのConsole API(Firefox 3とFirebugで始めるJavaScript開発:第2回 Firebugによるデバッグの基本,Console APIとその活用|gihyo.jp … 技術評論社)で用意されているメソッドです。(IE8でも使えるようである。)

wait(0.1).next(function (elapsed) {
    console.log(elapsed); //=> may be 90-110
});
console.log(1);

jQueryのgetJSONメソッドを使って複数のJSONファイルを非同期で処理する例を示す。

var results = [];
next(function () {
    return $.getJSON("foo.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    return $.getJSON("bar.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    return $.getJSON("baz.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    alert(results);
});

この処理は以下のように記述する事もできる。

var results = [];
$.getJSON("foo.json").next(function (data) {
    results.push(data);
}).
next(function () {
    return $.getJSON("bar.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    return $.getJSON("baz.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    alert(results);
});

parallel関数を使う事でもっと簡潔な記述をする事もできる。

parallel([
    $.getJSON("foo.json"),
    $.getJSON("bar.json"),
    $.getJSON("baz.json")
]).
next(function (results) {
    alert(results);
});

parallel関数の引数として連想配列を使う事もできる。

parallel({
    foo: $.getJSON("foo.json"),
    bar: $.getJSON("bar.json"),
    baz: $.getJSON("baz.json")
}).
next(function (results) {
    console.log(results.foo,results.bar,results.baz);
});

loop関数を使う事もできる。

var wants = ["foo.json", "bar.json", "baz.json"];
var results = [];
loop(wants.length, function (i) {
    return $.getJSON(wants[i]).next(function (data) {
        results.push(data);
    });
}).
next(function () {
    alert(results);
});

loop関数は以下のような引数の指定をする事もできる。

//=> loop 1 to 100
loop({begin:1, end:100, step:10}, function (n, o) {
    for (var i = 0; i < o.step; i++) {
        log(n+i);
    }
});

JSONファイルが存在しないなのどajacの処理中にエラーが発生した場合の処理をerror関数にて記述できます。

next(function () {
    return $.getJSON("xxx.json").next(function (data) {
        // 成功した場合の処理
    });
}).
error(function (e) {
    alert(e);
});

また、ajacの処理中にエラーが発生した場合に更に別のajaxの処理をおこなわせる等の複雑なエラーハンドリングを実行できます。
以下のコードではfoo.jsonまたはxxx.jsonの読み込みに失敗した場合に更にbar.jsonとbaz.jsonの読み込みを実行し成功した場合はalert(results)を実行し失敗した場合はalert(e)を実行します。

var results = [];
$.getJSON("foo.json").next(function (data) {
        results.push(data);
}).
next(function () {
    return $.getJSON("xxx.json").next(function (data) {
        results.push(data);
    });
}).
error(function (e) {
    return $.getJSON("bar.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    return $.getJSON("baz.json").next(function (data) {
        results.push(data);
    });
}).
next(function () {
    alert(results);
}).
error(function (e) {
    alert(e);
});

 

JavaScriptの参考書 /  Ajaxの参考書 /  JQueryの参考書 /  HTMLの参考書 /  CSSの参考書

 

ページのトップへ戻る