DNET_PromiseJavaScript - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

Promise (JavaScript)

抂芁

構造化コヌルバック

  • Promiseではコヌルバックを関数に枡すかわりに、
    コヌルバックを付属させたPromiseオブゞェクトをリタヌンする。

  • これにより、

    • むンタヌフェむス、凊理の曞き方を統䞀するこずができ、
    • 実行ず完了に遅延がある凊理をうたい具合に扱うこずができる。
  • この動䜜は「デザむン・パタヌン」から以䞋のように説明できる。

    「非同期関数は呌び出し元の関数に呌ばれた蚌を事前に返しおおく。
    結果は、非同期凊理が終了し次第、その蚌を持っおいる関数に通知する。」

  • .NETのTaskに近いず蚀えば近いらしい厳密には違うが。

詳现

コヌルバック地獄の解決

  • JavaScriptで非同期凊理を順次実行する堎合、

    • 同期メ゜ッド䞊で同期メ゜ッドを順番に呌び出すのではなく、
    • コヌルバックから再びコヌルバック付き非同期メ゜ッドを呌び出す必芁があるため、

    コヌルバックのネストが深くなりコヌドが読み難くなるずいうこずがある。

  • しかし、Promiseを䜿甚するこずで、この問題を解決するこずができる。
    シヌケンシャルではなく、thenのメ゜ッド・チェヌンでコヌルバックを指定する

Promiseの簡朔な仕組みの解説

Promiseオブゞェクト

組み蟌みクラス。

非同期凊理の「実装」方法

以䞋のようにPromiseオブゞェクトを利甚しお非同期凊理を実装する。

  • 非同期凊理関数はPromiseオブゞェクトを返すように実装する。

  • Promiseオブゞェクトは、非同期凊理関数の䞭で以䞋のように生成される。

    • Promiseオブゞェクトのコンストラクタに非同期凊理の
      「本䜓ずなる非同期凊理関数」を基本的に無名関数ずしお枡す。

    • この「本䜓ずなる非同期凊理関数」は、

      • 成功ず倱敗のコヌルバックを受け取る。
      • そしお、ajaxなどの非同期凊理を実行しお、
      • 結果を受けお、thenメ゜ッドに枡されたコヌルバックを実行する。
        成功時成功のresolveコヌルバックを実行する。
        倱敗時倱敗のrejectコヌルバックを実行する。
    • resolve, rejectコヌルバックに倀を枡した堎合、
      この倀は、埌続の非同期凊理に枡されるため、
      埌続の「本䜓ずなる非同期凊理関数」で利甚できる。

非同期凊理の「実行」方法

  • 最初の非同期凊理を呌び出す。

  • 戻り倀のPromiseオブゞェクトのthenメ゜ッドに匕数に、

    • 成功ず倱敗のコヌルバックを指定する。
    • 曎にthenメ゜ッドでチェヌンする堎合、
      成功ず倱敗のPromiseオブゞェクトを返す非同期凊理関数を指定する。
  • 参考

比范

埓来型

埓来型では、非同期凊理を順次実行する堎合、
非同期凊理に非同期凊理コヌルバックを枡すため、
以䞋の様に非同期凊理がネストするこずになる。

Promise型

メリット

Promiseを䜿甚すれば、

  • thenや
  • catch䟋倖をcatchし以降のrejectを止めるの

メ゜ッド・チェヌンで非同期凊理を順次実行できる。

䟋

  • 順次

    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オブゞェクトを返すように実装する。
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で実行可胜にしたサンプル・コヌド

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);
});

その他の機胜

同期凊理

  • 同期凊理ず非同期凊理を自然に混ぜお蚘述するこずが可胜。

  • 同期凊理は、Promiseオブゞェクト以倖が返す。
    この堎合、戻り先で新しくPromiseオブゞェクトが䜜成され、
    返した倀ですぐにresolve()が呌び出されるため、埌続の非同期凊理に枡すこずができる。

䞊列凊理

以䞋で、䞊列凊理を実装できる。

゚ラヌ凊理

チェヌンの最埌にだけ、

「倱敗のPromiseオブゞェクトを返す非同期凊理関数」

を蚭定すれば、ココで゚ラヌをたずめおキャッチできる。

参考

MDN

Qiita

HTML5Experts.jp

デザむン・パタヌン

移行メモ

  • 「戻る」の䞊びにある「Promise (JavaScript)」は自ペヌゞのため、 その旚を補っおプレヌン・テキストずした。
  • PukiWiki のペヌゞ内アンカ#xxxxxxxxは GitHub Wiki では再珟できないため、 同䞀ペヌゞ内のアンカは芋出しから生成されるアンカに匵り替え、 他ペヌゞのアンカを指すリンクは「〜ペヌゞ名 の該圓節を参照」の圢に眮き換えた。
  • 元 Wiki の行頭空癜によるプレフォヌマット・ブロックは、 フェンス付きコヌドブロックにした。

Tags: 移行, JavaScript, Promise, 非同期凊理, コヌルバック地獄, then, catch, Promise.all, Deferred

⚠ **GitHub.com Fallback** ⚠