この記事では、javascriptがプロミス、特にJQuery.Deferredを必要とする理由については説明しません。 参照情報も提供しません。インターネット上で十分です。 たとえば、
hereまたは
hereまたは
hereです。
この記事は、JQueryライブラリーのDeferredオブジェクトにすでに少し精通しているが、複雑なチェーン(キュー)を作成した経験のない技術者向けです。
準備する
ここで説明するすべてのコード例では、非同期メソッド
$ .ajax()を使用します。これは、約束のメソッド(完了、失敗、常に)を実装するいわゆるjqXHRを返します。 必要なのはそれらだけなので、$ .ajaxはプロミスを返すと仮定します。
一部の例では、JQueryライブラリの一部である$ .map()および$ .each()メソッドを使用しています。
順次実行
promiseの最も簡単な使用法は、非同期操作の順次実行です。 つまり、次の操作は、現在の操作が終了するまで開始されません。
$.ajax('http://echo.jsontest.com/id/1') .then(function(result){ console.log(JSON.stringify(result)); return $.ajax('http://echo.jsontest.com/id/2') }).then(function(result){ console.log(JSON.stringify(result)); return $.ajax('http://echo.jsontest.com/id/3') }).then(function(result){ console.log(JSON.stringify(result)); });
ここでの生きた例。
並列実行
すべての非同期操作を同時に開始し、すべての並列操作が完了した場合にのみ次のコールバックに進みます。
$.when( $.ajax('http://echo.jsontest.com/id/1'), $.ajax('http://echo.jsontest.com/id/2'), $.ajax('http://echo.jsontest.com/id/3') ).then(function(result1, result2, result3){ console.log(JSON.stringify(result1[0])); console.log(JSON.stringify(result2[0])); console.log(JSON.stringify(result3[0])); })
ここでの生きた例。
順次並列実行
タスク:1つの要求を実行し、その完了後にさらにいくつかの操作の並列実行を開始します。
$.ajax('http://echo.jsontest.com/id/1') .then(function(result1){ console.log(JSON.stringify(result1)); return $.when( $.ajax('http://echo.jsontest.com/id/2'), $.ajax('http://echo.jsontest.com/id/3'), $.ajax('http://echo.jsontest.com/id/4') ) }).then(function(result2, result3, result4){ console.log(JSON.stringify(result2[0])); console.log(JSON.stringify(result3[0])); console.log(JSON.stringify(result4[0])); })
生きている例 。
不明な数の非同期操作の並列実行
より困難な状況に移行します。 並列リクエストを作成する必要があるそれぞれのリンクを持つ配列があるとします。 タスクは、配列内のリンクの数が事前にわからないという事実によって複雑になります。
array = ['/url1', '/url2', ….. '/urlN']
並列$ .whenメソッドが次のように使用されることはすでにわかっています。
$.when(promise1, promise2, … promiseN)
しかし、残念ながら、このメソッドに一連のプロミスを渡すことはできません。 したがって、このコードは少し書き換える必要があり、それがタスクに適しています。
$.when.apply(this, [promise1, promise2, … promiseN])
そして、問題の完全な解決策は次のとおりです。
urls = ['http://echo.jsontest.com/id/1', 'http://echo.jsontest.com/id/2', 'http://echo.jsontest.com/id/3'] promises = $.map(urls, function(url){ return $.ajax(url).then(function(result){ console.log(JSON.stringify(result)); }); }); $.when.apply(this, promises) .then(function(){ console.log('done'); });
同じ
jsfiddleコード。
不明な数の非同期操作の順次実行
タスクは前の例と同じですが、リクエストは順番に送信する必要があります。 このアプローチは、リクエストが多数あり、Webアプリケーションのサーバー側がそのような負荷向けに設計されていない場合に役立ちます。
この問題を解決するために、サイクル内の約束のチェーンを「増やします」。
urls = ['http://echo.jsontest.com/id/1', 'http://echo.jsontest.com/id/2', 'http://echo.jsontest.com/id/3'] promise = $.when(); $.each(urls, function(index, url){ promise = promise.then(function(){ return $.ajax(url); }).then(function(result){ console.log(JSON.stringify(result)); }); }); promise.then(function(){ console.log('OK'); });
ここで、ちょっとしたトリックを適用しました:promise = $ .when()。 引数なしで$ .whenメソッドを実行すると、解決されたプロミスが返されます。これはチェーンの最初のリンクになります。
実行中のコードを
表示します。
シンプルなエラー処理:すべての操作に1つのハンドラー
エラー処理には、.failメソッドが使用されます。 以下の例では、このメソッドはPromiseのチェーンの最後にあり、エラーが発生すると、完了したコールバックはすべてスキップされます。
$.ajax('http://echo.jsontest.com/id/1') .then(function(){ console.log('OK 1'); return $.ajax('http://echo.jsontest.com/id/2'); }).then(function(){ console.log('OK 2'); return $.ajax('http://echo.jsontest_fail.com/id/3'); }).then(function(){ console.log('OK 3'); return $.ajax('http://echo.jsontest.com/id/4'); }).then(function(){ console.log('OK 4'); }).fail(function(){ console.log('error'); });
このコードを
実行します。
エラー処理後にチェーンを停止する
複数のエラーハンドラー(拒否されたプロミス)がチェーンで使用されている場合、エラーが発生すると、後続のすべての失敗コールバックが呼び出されます。 例:
$.ajax('http://echo.jsontest.com/id/1') .then(function(){ console.log('OK 1'); return $.ajax('http://echo.jsontest.com/id/2'); }).then(function(){ console.log('OK 2'); return $.ajax('http://echo.jsontest_fail.com/id/3'); }).fail(function(){ console.log('error 1'); }).then(function(){ console.log('OK 3'); return $.ajax('http://echo.jsontest.com/id/4'); }).fail(function(){ console.log('error 2'); }).then(function(){ console.log('OK 4'); }).fail(function(){ console.log('error 3'); });
このコードを実行すると、コンソールに次のように表示されます。
OK 1 OK 2 error 1 error 2 error 3
信じない人のための
リンク 。
しかし、ほとんどの場合、この動作は役に立ちません。 エラーを処理した後、後続のコールバックが呼び出されないことを確認します。
$.ajax('http://echo.jsontest_fail.com/id/1') .then(function(){ console.log('OK 1'); return $.ajax('http://echo.jsontest.com/id/2'); }, function(){ console.log('error 1'); return $.Deferred(); }).then(function(){ console.log('OK 2'); }, function(){ console.log('error 2'); })
結果を見てください。
この例では、2つの注意事項があります。 まず、エラーハンドラは、.thenメソッドの2番目の引数によって設定されるようになりました。 2番目-エラーハンドラーは、解決も拒否もされない遅延オブジェクト(約束)を返します。
エラー処理後のチェーン実行の継続
前の例を少し変更することで、エラーを処理した後に次の完了したコールバックが呼び出されるようにできます。
$.ajax('http://echo.jsontest_fail.com/id/1') .then(function(){ console.log('OK 1'); return $.ajax('http://echo.jsontest.com/id/2'); }, function(){ console.log('error 1'); return $.when(); }).then(function(){ console.log('OK 2'); }, function(){ console.log('error 2'); })
この例は、7行目のみが前の例と異なります。
おわりに
JQuery.Deferredコンポーネントは、最初に知り合ったときほど複雑ではありませんが、Promiseの機能を実装する他のライブラリは単純です。
UPD
コメントしてくれた
mayorovpに感謝