「[[.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

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS