Promise

by 3 contributors:

This translation is incomplete. Please help translate this article from English.

これは Harmony(ECMAScript 6) 提案の一部であり、実験段階の技術です。
この技術の仕様は安定していません。ブラウザ互換性の一覧表を確認してください。またこれらの構文や動作は、仕様変更などにより、新しいバージョンのブラウザでは変更される可能性があるという点に注意してください。

Promiseオブジェクトは処理の延期(deferred)と非同期処理のために使われます。Promiseはまだ完了していないが、いずれ完了する処理を表します。

構文

new Promise(executor);
new Promise(function(resolve, reject) { ... });

引数

executor
2つの引数resolverejectを持つ関数オブジェクト。1番目の引数はプロミスが成功した場合、2番目の引数は失敗した場合です。処理が完了したとき、これらの関数を呼ぶことができます。

説明

Promise インターフェースは作成時点では分からなくてもよい値へのプロキシです。プロミスを用いることで、非同期アクションの成功や失敗に対するハンドラを関連付けることができます。これにより、非同期メソッドは、最終的な値を返すのではなく、未来のある時点で値を持つプロミスを返すことで、同期メソッドと同じように値を返すことができるようになります。

Promiseの状態は次のうちの1つです:

  • pending: 初期状態。成功も失敗もしていません。
  • fulfilled: 処理が成功して完了したことを意味します。
  • rejected: 処理が失敗したことを意味します。

pendingのプロミスは、何らかの値をもってfulfilled、もしくは何らかの理由をもってrejectedとなることができます。そのどちらとなっても、then メソッドによって関連付けられたハンドラが呼ばれます。(対応するハンドラがアタッチされたとき、既にプロミスが成功または失敗していても、そのハンドラは呼ばれます。よって、同期処理とそのハンドラのアタッチと競合は発生しません。)

Promise.prototype.then メソッドと Promise.prototype.catch メソッドはプロミス値を返すので、連鎖させることができます—この処理はcompositionと呼ばれます。

Note: A promise is said to be settled if it is either fulfilled or rejected, but not pending. You will also hear the term resolved used with promises — this means that the promise is settled, or it is locked into a promise chain. Domenic Denicola's States and fates contains more details about promise terminology.

プロパティ

Promise.length
プロパティの長さである1(コンストラクタの引数の数)。
Promise.prototype
Promiseコンストラクタのプロトタイプ。

メソッド

Promise.all(iterable)
iterable 中の全てのプロミスが成功したときに成功するプロミスを返します。結果は全てのプロミスから得られた値の配列として渡されます。iterable 中にプロミスでないものが渡された時は、Promise.cast で変換されます。渡されたプロミスの内いずれかが失敗となれば、直ちに失敗したプロミスの結果をもって失敗となり、他のプロミスの結果は無視されます。
Promise.race(iterable)
iterable 中のプロミスの内、最初に完了 (成功または失敗) したプロミスによって成功または失敗するプロミスを返します。
Promise.reject(reason)
与えられた理由で失敗となる Promise オブジェクトを返します。
Promise.resolve(value)
与えられた値で成功となる Promise オブジェクトを返します。もし値が thenable (then メソッドを持っているオブジェクト) ならば、返されるプロミスはその thenable に従い、その結果を採用します。そうでなければ、返されるプロミスは与えられた値で成功します。

Promise プロパティ

プロパティ

Promise.prototype.constructor
インスタンスのプロトタイプを生成した関数を返します。デフォルトで、Promise関数です。

メソッド

Promise.prototype.catch(onRejected)
プロミスに失敗ハンドラコールバックを付加します。呼ばれるとコールバックの戻り値、または、プロミスが代わりに満たされているなら、オリジナル成功値によって完了している新しいプロミスを返します。
Promise.prototype.then(onFulfilled, onRejected)
プロミスに成功ハンドラと失敗ハンドラを付加します。呼ばれたハンドラの戻り値によって解決している新しいプロミスを返します。

Creating a Promise

以下の例は Promise の仕組みを示したものです。testPromise() メソッドは、 window.setTimeout を用いて、1秒から3秒のランダムな時間の後、メソッドがこれまでに呼ばれた回数で成功するプロミスを作成します。

プロミスの成功は、p1.then で設定されたコールバックによって記録されます。この記録から、メソッドの同期処理部分が、プロミスによる非同期処理からどのように分離されているかがわかります。

'use strict';
var promiseCount = 0;

function testPromise() {
  var thisPromiseCount = ++promiseCount;

  var log = document.getElementById('log');
  log.insertAdjacentHTML('beforeend', thisPromiseCount + ') 開始 (<small>同期処理開始</small>)<br/>');

  // 新しいプロミスを作成: 1~3秒後に結果を返すことを約束します
  var p1 = new Promise(
    // リゾルバ関数はプロミスの成功または失敗に応じて呼ばれます
    function(resolve, reject) {
      log.insertAdjacentHTML('beforeend', thisPromiseCount + ') プロミス開始 (<small>非同期処理開始</small>)<br/>');
      // 非同期を作成するための一例です
      window.setTimeout(
        function() {
          // 約束を果たしました!
          resolve(thisPromiseCount); 
        }, Math.random() * 2000 + 1000);
    });

  // プロミスが成功した時に何をするかを定めます
  p1.then(
    // メッセージと値を記録します
    function(val) {
      log.insertAdjacentHTML('beforeend', val + ') プロミス成功 (<small>非同期処理終了</small>)<br/>');
    });

  log.insertAdjacentHTML('beforeend', thisPromiseCount + ') プロミスは作成されました (<small>同期処理終了</small>)<br/>');
}

この例はボタンをクリックすると実行されます。あなたのブラウザがPromiseに対応している必要があります。短い時間の間に何度かボタンをクリックすると、それぞれのプロミスが次々と成功するのがわかります。

new XMLHttpRequest()を使った例

プロミスの生成

この例はXMLHttpRequestの成功または失敗をPromiseを使って報告するメソッドの実行を示しています。

'use strict';

// A-> $http function is implemented in order to follow the standard Adapter pattern
function $http(url){
 
  // A small example of object
  var core = {

    // Method that performs the ajax request
    ajax : function (method, url, args) {

      // Creating a promise
      var promise = new Promise( function (resolve, reject) {

        // Instantiates the XMLHttpRequest
        var client = new XMLHttpRequest();
        var uri = url;

        if (args && (method === 'POST' || method === 'PUT')) {
          uri += '?';
          var argcount = 0;
          for (var key in args) {
            if (args.hasOwnProperty(key)) {
              if (argcount++) {
                uri += '&';
              }
              uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
            }
          }
        }

        client.open(method, uri);
        client.send();

        client.onload = function () {
          if (this.status == 200) {
            // Performs the function "resolve" when this.status is equal to 200
            resolve(this.response);
          } else {
            // Performs the function "reject" when this.status is different than 200
            reject(this.statusText);
          }
        };
        client.onerror = function () {
          reject(this.statusText);
        };
      });

      // Return the promise
      return promise;
    }
  };

  // Adapter pattern
  return {
    'get' : function(args) {
      return core.ajax('GET', url, args);
    },
    'post' : function(args) {
      return core.ajax('POST', url, args);
    },
    'put' : function(args) {
      return core.ajax('PUT', url, args);
    },
    'delete' : function(args) {
      return core.ajax('DELETE', url, args);
    }
  };
};
// End A

// B-> Here you define its functions and its payload
var mdnAPI = 'https://developer.mozilla.org/en-US/search.json';
var payload = {
  'topic' : 'js',
  'q'     : 'Promise'
};

var callback = {
  success : function(data){
     console.log(1, 'success', JSON.parse(data));
  },
  error : function(data){
     console.log(2, 'error', JSON.parse(data));
  }
};
// End B

// Executes the method call 
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success) 
  .catch(callback.error);

// Executes the method call but an alternative way (1) to handle Promise Reject case 
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success, callback.error);

// Executes the method call but an alternative way (2) to handle Promise Reject case 
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success)
  .then(undefined, callback.error);

開発ツールでプロミスを使う簡単な例

これらの例の狙いは、プロミスの異なる使い方を紹介することです。

var p = Promise.resolve().then(function() {
  console.log('Promise resolve callback');
}, function() {
  console.log('Promise reject callback');
});


var p = Promise.reject().then(function() {
  console.log('Promise resolve callback');
}, function() {
  console.log('Promise reject callback');
});

XHRによる画像の読み込み

PromiseXMLHttpRequestで画像を読み込む別の例は、MDN GitHub promise-testリポジトリにあります。それぞれの行のコメントでプロミスとXHRの構造がよくわかるはずです。

仕様

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Promise' in that specification.
Standard Initial definition in an ECMA standard.

ブラウザ互換性

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 32.0 29.0 (29.0) [1] Edge 19 7.1
Feature Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support 未サポート 32.0 29.0 (29.0) [1] 未サポート 未サポート 8 32.0

[1] Gecko 24 は Future という名前で Promise の実験的な実装を持っています。Gecko 25 で Promise に名称が変更されましたが、Promise を使用するための dom.promise.enabled フラグはデフォルトで無効になっています。Bug 918806 によって、Gecko 29 から Promise はデフォルトで有効になりました。

関連リンク

ドキュメントのタグと貢献者

Contributors to this page: maruhiro, teoli, Susisu
最終更新者: maruhiro,