遅延オブジェクトはjQuery 1.5で登場しました。 アクションの結果に依存するロジックをアクション自体から分離できます。 JavaScriptの場合、Deferredオブジェクトは新しいものではなく、すでにMochiKitとDojoにありましたが、Julian AubourgからjQuery ajaxロジックが変更されたため、Deferredオブジェクトの導入は避けられませんでした。 遅延オブジェクトを使用すると、いくつかのコールバックをタスクの結果に関連付けることができ、それらのいずれかを実行開始後でもアクションに関連付けることができます。 進行中のタスクは非同期かもしれませんが、必要ではありません。
遅延オブジェクトは$ .ajax()に埋め込まれるようになったため、自動的に受け取ります。 次のように、ハンドラーを結果に関連付けることができます。
単一の成功、エラー、または完了ハンドラーに制限されなくなりました;単純なコールバック関数の代わりに、自己組織化コールバックキュー(FIFO)があります。
上記の例に示すように、コールバックは、AJAX要求の後、またはタスクの完了後でもフックできます。 これはコードを整理するのに最適です;長いコールバックブロックの日は番号が付けられます。
より深く掘り下げて、いくつかの同時AJAXリクエストの後に関数を呼び出したい状況を想像してください。 これは、遅延オブジェクトヘルパー-$ .when()を使用すると簡単です。
function doAjax(){ return $.get('foo.htm'); } function doMoreAjax(){ return $.get('bar.htm'); } $.when( doAjax(), doMoreAjax() ) .then(function(){ console.log( 'I fire once BOTH ajax requests have completed!' ); }) .fail(function(){ console.log( 'I fire if one or more requests failed.' ); });
JsFiddleの
例jsfiddle.net/ehynds/Mrqf8これは、すべてのjQuery AJAXメソッドが、非同期呼び出しを追跡するために使用されるPromiseオブジェクトを含むオブジェクトを返すため、すべて機能します。 Promiseは、アクションの結果の読み取り可能なオブザーバーです。 遅延オブジェクトは、promise()メソッドの可用性を調べて、オブジェクトを監視できるかどうか(オブジェクトが監視可能かどうか)を判断します。 $ .when()は、すべてのAJAXリクエストの実行を待機します。これが発生すると、.then()および.fail()を介して$ .when()にアタッチされたコールバック関数がタスクの結果に応じて呼び出されます。 コールバック関数は、到着順に呼び出されます(FIFOキュー)。
すべての遅延メソッド(.then()および.fail())は関数または関数の配列を受け入れるため、独自の動作を作成し、1回の呼び出しですべて割り当てたり、必要に応じてそれらを分離したりできます。
$ .ajax()は、別のDeferredのようなオブジェクトを含む非標準オブジェクトを返します。 約束()についてはすでに説明しましたが、その場合()、成功()、エラー()なども見つかりました。 Ajax-Deferredオブジェクト全体にアクセスすることはできません。 promise()、コールバックメソッド、およびisRejected()およびisResolved()メソッドのみ。これらはDeferredオブジェクトのステータスを確認するために使用できます。
しかし、なぜオブジェクト全体を返さないのでしょうか? その場合、Ajaxの応答を待つことなく、プログラムでAjax-Deferredオブジェクトを完成させることができます。 これは潜在的にパラダイム全体に違反します。
コールバックを登録する
上記の例では、deferredオブジェクトにコールバック関数を登録するためにthen()、success()、およびfail()メソッドが使用されていますが、特にAjax-Deferredを使用する場合は、さらに多くのメソッドを使用できます。
メソッドはすべてのDeferredオブジェクト(AJAX、$ .whenおよび手動で作成されたもの)で使用できます。
.then( doneCallbacks, failedCallbacks ) .done( doneCallbacks ) .fail( failCallbacks )
Ajax-Deferredオブジェクトには、上記のメソッドを単純に複製する3つの追加メソッドがあります。 これらはセマンティックの代替手段を提供し、私たち全員が慣れている古いハンドラーと名前が似ています:
.complete( doneCallbacks, failCallbacks ) .success( doneCallbacks ) .error( failCallbacks )
したがって、次の3つの例は同等です(成功は、AJAXリクエストのコンテキストにある場合よりも読み取りが優れていますよね?)
$.get("/foo/").done( fn );
遅延動作を作成する
$ .ajaxおよび$ .whenメソッドは内部的に遅延APIを提供することを知っていますが、独自のバージョンを作成することもできます。
function getData(){ return $.get('/foo/'); } function showDiv(){ var dfd = $.Deferred(); $('#foo').fadeIn( 1000, dfd.resolve ); return dfd.promise(); } $.when( getData(), showDiv() ) .then(function( ajaxResult ){ console.log('The animation AND the AJAX request are both done!');
JsFiddleの
例jsfiddle.net/ehynds/JSw5yshowDiv()内で、アニメーションを実行してプロミスを返す新しいDeferredオブジェクトを作成します。 fadeIn()が完了した後、遅延完了(jQueryのキューメソッドに精通している場合はdequeue()を忘れないでください)。 promiseが戻ってDeferredが終了するまでの間に、両方のタスクが正常に完了するまで待機するコールバックを登録します。 したがって、両方のタスクが完了すると、コールバックが実行されます。
getData()は、$ .when()がアクションの進行状況を監視できるようにするpromiseメソッドを持つオブジェクトを返します。 同様のオブジェクトはshowDiv()を返します
遅延オブジェクト
getData()およびshowDiv()で個々のコールバック関数を登録し、1つのmaster-Deferredオブジェクトにそれらのプロミスを登録するための別のステップを実行できます。
成功したgetData()または成功したshowDiv()を個別に実行した後、およびgetData()とshowDiv()の両方の成功後に何かを実行したい場合は、個々のDeferredオブジェクトのコールバックを登録し、 $ .when
function getData(){ return $.get('/foo/').success(function(){ console.log('Fires after the AJAX request succeeds'); }); } function showDiv(){ var dfd = $.Deferred(); dfd.done(function(){ console.log('Fires after the animation succeeds'); }); $('#foo').fadeIn( 1000, dfd.resolve ); return dfd.promise(); } $.when( getData(), showDiv() ) .then(function( ajaxResult ){ console.log('Fires after BOTH showDiv() AND the AJAX request succeed!');
JsFiddleの
例jsfiddle.net/ehynds/W3cQc遅延チェーン
Promiseはコールバックメソッドから返されるため、遅延コールバックはチェーンとして表すことができます。
@ajpianoの実際の例を
次に示します。
function saveContact( row ){ var form = $.tmpl(templates["contact-form"]), valid = true, messages = [], dfd = $.Deferred(); if( !valid ){ dfd.resolve({ success: false, errors: messages }); } else { form.ajaxSubmit({ dataType: "json", success: dfd.resolve, error: dfd.reject }); } return dfd.promise(); }; saveContact( row ) .then(function(response){ if( response.success ){
saveContact()関数は、フォームを検証し、結果を有効な変数に保存します。 検証に失敗した場合、遅延ブール値とエラー配列を含むオブジェクトで遅延オブジェクトが終了します。 フォームが検証に合格した場合、遅延オブジェクトは終了しますが、今回はAJAXリクエストからの応答で終了します。 fail()ハンドラーはトランスポートエラー(404、500など)をリッスンします
観察できないタスク
遅延は、実行ロジックが非同期である場合と非同期でない場合があり、メインコードからこの条件を抽象化する場合に特に役立ちます。 タスクはプロミスを返す場合がありますが、文字列、オブジェクト、または他の何かを返す場合もあります。
この例では、「アプリケーションの起動」リンクを初めてクリックすると、AJAXリクエストはサーバーに現在のタイムスタンプを保存して返すように指示します。 タイムスタンプは、AJAXリクエストの実行後に要素のデータキャッシュに保存されます。 アプリケーションは最初のクリックのみを考慮します。 その後のクリックでは、タイムスタンプはサーバーにリクエストする代わりに、データキャッシュから取得されます。
function startTask( element ){ var timestamp = $.data( element, 'timestamp' ); if( timestamp ){ return timestamp; } else { return $.get('/start-task/').success(function( timestamp ){ $.data( element, 'timestamp', timestamp ); }); } } $('#launchApplication').bind('click', function( event ){ event.preventDefault(); $.when( startTask(this) ).done(function( timestamp ){ $('#status').html( '<p>You first started this task on: ' + timestamp + '</p>'); }); loadApplication(); });
$ .when()がその最初の引数に約束がない(したがって、観測できない)ことを認識すると、新しい遅延オブジェクトを作成し、データオブジェクトで終了し、この遅延オブジェクトの約束を返します。 そのため、約束のないオブジェクトは観察可能になります。
1つ小さなことですが、promiseメソッドでオブジェクトを返すオブジェクトの起動を遅らせることはできません。 遅延オブジェクトはpromiseメソッドの可用性によって決まりますが、jQueryはpromiseが必要なオブジェクトを返すかどうかをチェックしません。 したがって、このコードには構文エラーが含まれています。
var obj = { promise: function(){
おわりに
遅延オブジェクトは、非同期タスクを記述するための新しい信頼できる方法を導入します。 コールバックロジックを1つのコールバックに整理する方法に焦点を当てる代わりに、いくつかの個別のアクションをコールバックキューに割り当てて、それらの同期をあまり気にせずに実行されることを認識できます。 提案された情報は長い間ダイジェストする必要がありますが、すべてを学ぶと、Deferredオブジェクトを使用すると非同期コードがはるかに簡単になることを理解できると思います。