「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfrastructure.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>JavaScriptのスレッド処理]] --Promise (JavaScript) --[[async/await (JavaScript)]] *目次 [#a60edc5a] #contents *概要 [#o92c9b54] 構造化コールバック -Promiseではコールバックを関数に渡すかわりに、~ コールバックを付属させたPromiseオブジェクトをリターンする。 -これにより、 --インターフェイス、処理の書き方を統一することができ、 --実行と完了に遅延がある処理をうまい具合に扱うことができる。 -この動作は「[[デザイン・パターン>#c39497f8]]」から以下のように説明できる。 >「非同期関数は呼び出し元の関数に呼ばれた証を事前に返しておく。~ 結果は、非同期処理が終了し次第、その証を持っている関数に通知する。」 -.NETのTaskに近いと言えば近いらしい(厳密には違うが)。 --参考:[C#]TaskクラスをJavaScriptのPromiseっぽく使ってみる実験 - Qiita~ https://qiita.com/matarillo/items/40fbdc4223689a1e6c43 *詳細 [#v092daea] **コールバック地獄の解決 [#a28302bb] -JavaScriptで非同期処理を順次実行する場合、 --同期メソッド上で同期メソッドを順番に呼び出すのではなく、 --コールバックから再びコールバック付き非同期メソッドを呼び出す必要があるため、 >コールバックのネストが深くなりコードが読み難くなるということがある。 -しかし、Promiseを使用することで、この問題を解決することができる。~ (シーケンシャルではなく、thenのメソッド・チェーンでコールバックを指定する) **Promiseの簡潔な仕組みの解説 [#kecb11f2] ***Promiseオブジェクト [#le281168] 組み込みクラス。 ***非同期処理の「実装」方法 [#nedffe32] 以下のようにPromiseオブジェクトを利用して非同期処理を実装する。 -非同期処理関数はPromiseオブジェクトを返すように実装する。 -Promiseオブジェクトは、非同期処理関数の中で以下のように生成される。 --Promiseオブジェクトのコンストラクタに非同期処理の~ 「本体となる非同期処理関数」を(基本的に無名関数として)渡す。 --この「本体となる非同期処理関数」は、 ---成功と失敗のコールバックを受け取る。 ---そして、ajaxなどの非同期処理を実行して、 ---結果を受けて、thenメソッドに渡されたコールバックを実行する。~ 成功時:成功のresolveコールバックを実行する。~ 失敗時:失敗のrejectコールバックを実行する。 --resolve, rejectコールバックに値を渡した場合、~ この値は、後続の非同期処理に渡されるため、~ 後続の「本体となる非同期処理関数」で利用できる。 ***非同期処理の「実行」方法 [#i4ec53f2] -最初の非同期処理を呼び出す。 -戻り値のPromiseオブジェクトのthenメソッドに引数に、 --成功と失敗のコールバックを指定する。 --更にthenメソッドでチェーンする場合、~ 成功と失敗のPromiseオブジェクトを返す非同期処理関数を指定する。 -参考 --Promise.prototype.then() - JavaScript | MDN~ https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then *比較 [#bd8709b1] **[[従来型>JavaScriptのスレッド処理#c0bd2b83]] [#pb83b30e] 従来型では、非同期処理を順次実行する場合、~ 非同期処理に非同期処理(コールバック)を渡すため、~ 以下の様に非同期処理がネストすることになる。 **Promise型 [#wa2894a4] ***メリット [#z9541f12] Promiseを使用すれば、 -thenや -catch(例外をcatchし以降のrejectを止める)の メソッド・チェーンで非同期処理を順次実行できる。 ***例 [#e50c21ad] -順次 var promise1 = fetchSomething1(); var promise2 = promise1.then(fetchSomething2); var promise3 = promise2.then(fetchSomething3); var promise4 = promise2.then(fetchSomething4); promise4.then(doSomethingFinally); -メソッド・チェーン fetchSomething1() .then(fetchSomething2) .then(fetchSomething3) .then(fetchSomething4) .then(doSomethingFinally); >※ 各非同期処理(fetchSomething、doSomething)は、~ Promiseオブジェクトを返すように実装されている。 >※ 各非同期処理に「値を渡したり」・「処理を追加したり」する場合は以下のようにする。 .then( function(rtn) { alert(rtn); return fetchSomething2(rtn); }).then(... -参考 --Promise.prototype.catch() - JavaScript | MDN~ https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch *サンプル・コード [#e43aadb1] **ダミー非同期関数を使用したサンプル・コード [#ma426702] // 非同期処理関数はPromiseオブジェクトを返すように実装する。 var fetchSomething1 = function() { // Promiseオブジェクトは、非同期処理関数の中で以下のように生成される。 return new Promise( // Promiseオブジェクトのコンストラクタに非同期処理の // 「本体となる非同期処理関数」を(基本的に無名関数として)渡す。 // この「本体となる非同期処理関数」は、成功と失敗のコールバックを受け取る。 function(resolve, reject) { // そして、ajaxなどの非同期処理を実行して、 // 結果を受けて、thenメソッドに渡されたコールバックを実行する。 AsynchronousProcessingWrapper({ success: function(data) { // 成功した場合 // 成功のコールバックを実行する。 resolve('成功1'); }, fail: function() { // 失敗した場合 // 失敗のコールバックを実行する。 reject('失敗1'); } }); } // resolve, rejectコールバックに値を渡した場合、 // この値は、後続の非同期処理に渡されるため、 // 後続の「本体となる非同期処理関数」で利用できる。 ); }; // fetchSomething1 と同じ。 var fetchSomething2 = function(str) { return new Promise(function(resolve, reject) { AsynchronousProcessingWrapper({ success: function(data) { // 成功した場合 resolve(str + ' 成功2'); }, fail: function() { // 失敗した場合 reject(str + ' 失敗2'); } }); }); }; fetchSomething1().then(function(rtn) { alert(rtn); return fetchSomething2(rtn); }, function(error) { alert('error:' + error); return fetchSomething2(error); }).then(function(rtn) { alert(rtn); }, function(error) { alert('error:' + error); }); **developer.mozilla.orgで実行可能にしたサンプル・コード [#vcede906] https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then ※ ダミー非同期関数を削除した。~ ※ resolveをrejectに切り替えると動作を変更させることができる。 var fetchSomething1 = function() { return new Promise(function(resolve, reject) { resolve('成功1'); //reject('失敗1'); }); }; var fetchSomething2 = function(str) { return new Promise(function(resolve, reject) { resolve(str + ' 成功2'); //reject(str + ' 失敗2'); }); }; fetchSomething1().then(function(rtn) { alert(rtn); return fetchSomething2(rtn); }, function(error) { alert('error:' + error); return fetchSomething2(error); }).then(function(rtn) { alert(rtn); }, function(error) { alert('error:' + error); }); *その他の機能 [#w20917ca] **同期処理 [#s2e75bf6] -同期処理と非同期処理を自然に混ぜて記述することが可能。 -同期処理は、Promiseオブジェクト以外が返す。~ この場合、戻り先で新しくPromiseオブジェクトが作成され、~ 返した値ですぐにresolve()が呼び出されるため、後続の非同期処理に渡すことができる。 **並列処理 [#j1da9245] 以下で、並列処理を実装できる。 -Promise.all() - JavaScript | MDN~ https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all **エラー処理 [#m6f12f61] チェーンの最後にだけ、 >「失敗のPromiseオブジェクトを返す非同期処理関数」 を設定すれば、ココでエラーをまとめてキャッチできる。 *参考 [#n692e9ec] -Promiseでコールバック地獄から解放された話~ https://www.slideshare.net/sotasugiura/slide-43304678 -Promiseによる非同期処理の書き方 - 30歳からのプログラミング~ http://numb86-tech.hatenablog.com/entry/2017/01/02/152517 **MDN [#dddcaecf] -JavaScript --Promise~ https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise --Using promises~ https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises **Qiita [#da7003c4] -今更だけどPromise入門~ https://qiita.com/koki_cheese/items/c559da338a3d307c9d88 -Promiseについて0から勉強してみた~ https://qiita.com/toshihirock/items/e49b66f8685a8510bd76 -Promiseのpolyfill(IE11お前もか!) - Qiita~ https://qiita.com/zERobYTezERo/items/ac458c4cf2a8f2f6c3dd -Promise再入門 > ① ~Promise基本編~~ https://qiita.com/gctfuji/items/1dfe4265c36bea903ab3 -jQuery Deferredまとめ~ https://qiita.com/hththt/items/9f193fc10b79cdeea903 **HTML5Experts.jp [#a1c3ad29] -連載 | ECMAScript 2015(ECMAScript 6)特集~ https://html5experts.jp/series/ecma2015/ --Promiseで簡単!JavaScript非同期処理入門 ---【前編】~ https://html5experts.jp/takazudo/17107/ ---【後編】~ https://html5experts.jp/takazudo/17113/ **デザイン・パターン [#c39497f8] -future - Wikipedia~ https://ja.wikipedia.org/wiki/Future -Promise/Deferred パターン - 野次馬エンジニア道~ http://notta55.hatenablog.com/entry/2014/09/20/144054 -非同期処理とPromise(Deferred)を背景から理解しよう - hifive~ https://www.htmlhifive.com/conts/web/view/study-room/async-programming-with-deferred