Skip to content

DNET_PromiseJavaScript

nishi_74322014 edited this page Sep 11, 2026 · 1 revision

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

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally