Mochikit.Asyncのサンプルコードを読む
Mochikit.Asyncのドキュメントのサンプルコードを、バラバラにして見ていきます。
以下はMochiKit.Async/META.jsonファイルを読み込みスクリプト自身が使っているMochiKit.Asyncバージョンが最新かどうかをチェックするコードです。
var url = "/src/b/bo/bob/MochiKit.Async/META.json"; /* META.json looks something like this: {"name": "MochiKit", "version": "0.5"} */ var d = loadJSONDoc(url); var gotMetadata = function (meta) { if (MochiKit.Async.VERSION == meta.version) { alert("You have the newest MochiKit.Async!"); } else { alert("MochiKit.Async " + meta.version + " is available, upgrade!"); } }; var metadataFetchFailed = function (err) { alert("The metadata for MochiKit.Async could not be fetched :("); }; d.addCallbacks(gotMetadata, metadataFetchFailed);
loadJSONDoc
引数で指定したURLに配置されているJSONファイルをXMLHttpRequestで読み込みます。
戻り値としてDeferredオブジェクトが返されます。Deferredについては後ほど。
MochiKit.Async.VERSION
MochiKit.Asyncのバージョン値です。同様にMochiKit.Async.Nameメンバも存在します。
gotMetadataの引数metaにはloadJSONDoc(url)で取得したMETA.jsonインスタンスが渡されます。ここでは実行している環境でのMochiKit.Asyncバージョンとjsonファイルに記録されているバージョン値を比較し、最新かどうかをチェックしています。
metadataFetchFailedにはloadJSONDocエラー時の処理が書かれています。ここでの処理内容はalertしているだけです。
addCallbacks
DeferredにloadJSONDoc()成功時のコールバック処理gotMeradata()と、失敗時のコールバック処理(MochiKitではerrbackと呼ぶ)metadataFetchFailed()を登録しています。
Deferredとは
MochiKitでは時間のかかる処理、応答待ちする処理のためにコールバック関数を登録して非同期処理を行います。非同期要求の結果が得られたときに実行する一連の関数(この一連の関数のことをコールバックチェインと呼ぶ)と非同期要求エラー時に呼ばれる一連のエラー処理関数(エラーバックチェイン)をDeferredに接続します。MochiKitは非同期要求結果が得られた時点でコールバックチェイン先頭からコールバックを呼び出すか、エラー発生時にはエラーバックを呼び出します。Deferredオブジェクトは各コールバックまたはエラーバックの結果をチェインの次の関数へ渡します。
コールバック/エラーバックチェイン
コールバックシーケンスは内部的にcallback/errbackペアを含む2組のリストとして表現されています。例えば以下のような呼び出しシーケンスは、
var d = new Deferred(); d.addCallback(myCallback); d.addErrback(myErrback); d.addBoth(myBoth); d.addCallbacks(myCallback, myErrback);
次のような内部表現のDeferredに変換されます。
[ [myCallback, null], [null, myErrback], [myBoth, myBoth], [myCallback, myErrback] ]
Deferredは現在状態の経過も記録します。状態は次の3つの値のどれかになります。
Value Condition -1 no value yet (initial condition) 0 success 1 error
次のどれかの状態となった場合、Deferedはエラー状態となります。
- callbackまたはerrbackに与えられた結果が"instanceof Error"
- callbackまたはerrback実行中にエラーを投げた
そうでない場合はDeferredは成功状態となります。Deferredの状態は実行するコールバックシーケンス中の次の要素を決定します。
上記の例のdeferredチェインでcallbackまたはerrbackが発生した場合、次のようなことが起こります(例外が発生し、そのままリターンした状態を想像してください)。
// d.callback(result) or d.errback(result) if (!(result instanceof Error)) { result = myCallback(result); } if (result instanceof Error) { result = myErrback(result); } result = myBoth(result); if (result instanceof Error) { result = myErrback(result); } else { result = myCallback(result); }
コールバックシーケンスに新たなステップが加えられた場合に結果は保存されます。Deferredが既に値を利用できる場合、新規に加えられたコールバックは即座に呼び出されます。
動作サンプル
Deferredの動作理解のための簡単なサンプルです。MochiKitのAJAX Tableデモで使われているdomains.jsonを読み込み、コールバックチェインで値を順番に読み込みます。チェインの動作確認のためにわざとコールバックチェインを3回にわけています。
deferred sample