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

構文

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

引数

executor
2つの引数resolverejectを通してほかの関数に処理を渡すを持つ関数。1番目の引数はプロミスが成功した場合、2番目の引数は失敗した場合です。処理が完了したとき、これらの関数を呼ぶことができます。
executor 関数はPromiseが実装されたときに即時に実行されます。(作成されたオブジェクトが返される時ですらexecutorはPromiseコンストラクタの前に呼ばれる)。 resolve関数やreject関数はpromiseにバインドされて、それらを呼び出され、それぞれfulfill状態もしくはreject状態になります。executorは非同期の作業を開始して、完了したときpromiseの最終的な値を処理するためにresolveあるいは、もしエラーが起きたらrejectが呼び出されます。

説明

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

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

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

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

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

混乱を避けるために: Scheme に代表されるいくつかの言語では遅延評価ができたり、計算を延期する機構を持っています。それらのことも "Promise" と呼ばれます。のメカニズムを持っていたり、計算を延期する機構を持っており、それらはまた、"Promise"と呼ばれます。JavaScript での Promise は、すでに起きつつある処理を表します。そしてその処理はコールバックを連鎖的に呼べます。JavaScript で遅延評価は、引数なしのアロー関数で実現できます:f = () => expression によって遅延評価される式が作成され、f を呼ぶことでその式を評価できます。

付記: Promise は pending ではなく fullfilled か failed のどちらかになると言われています。また解決 (resolved) という用語も目にされたことがあると思います。解決とは、Promise の値が決まること、もしくは Promise チェーンに入ったことを意味します。Domenic Denicola'の States and fates  では、Promise で使用される用語についてより詳細に述べられています。

プロパティ

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

メソッド

Promise.all(iterable)
iterable 中の全てのプロミスが成功したときに成功するプロミスを返します。結果は全てのプロミスから得られた値の配列として渡されます。iterable 中にプロミスでないものが渡された時は、Promise.resolve で変換されます。渡されたプロミスの内いずれかが失敗となれば、直ちに失敗したプロミスの結果をもって失敗となり、他のプロミスの結果は無視されます。
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)
プロミスに成功ハンドラと失敗ハンドラを付加します。呼ばれたハンドラの戻り値によって解決している新しいプロミスを返します。

Promiseを作成する

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

プロミスの成功は、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/>');
    })
  .catch(
    // Log the rejection reason
    function(reason) {
      console.log('Handle rejected promise ('+reason+') here.');
    });

  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 && this.status < 300) {
            // Performs the function "resolve" when this.status is equal to 2xx
            resolve(this.response);
          } else {
            // Performs the function "reject" when this.status is different than 2xx
            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)
Promise の定義
標準 Initial definition in an ECMA standard.
ECMAScript 2017 Draft (ECMA-262)
Promise の定義
ドラフト  

ブラウザ互換性

機能 Chrome Edge Firefox Internet Explorer Opera Safari Servo
Promise32.0(有り)29.01サポートなし197.12サポートなし
Promise.all32.0(有り)29.0サポートなし197.1サポートなし
Promise.prototype32.0(有り)29.0サポートなし197.1サポートなし
Promise.prototype.catch32.0(有り)29.0サポートなし197.1サポートなし
Promise.prototype.then32.0(有り)29.0サポートなし197.1サポートなし
Promise.race32.0(有り)29.0サポートなし197.1サポートなし
Promise.reject32.0(有り)29.0サポートなし197.1サポートなし
Promise.resolve32.0(有り)29.0サポートなし197.1サポートなし
機能 Android Chrome for Android Edge Mobile Firefox for Android IE Mobile Opera Mobile Safari Mobile
Promise4.4.432.0(有り)291サポートなし(有り)8.02
Promise.all4.4.432.0(有り)29サポートなし(有り)8.0
Promise.prototype4.4.432.0(有り)29サポートなし(有り)8.0
Promise.prototype.catch4.4.432.0(有り)29サポートなし(有り)8.0
Promise.prototype.then4.4.432.0(有り)29サポートなし(有り)8.0
Promise.race4.4.432.0(有り)29サポートなし(有り)8.0
Promise.reject4.4.432.0(有り)29サポートなし(有り)8.0
Promise.resolve4.4.432.0(有り)29サポートなし(有り)8.0

1. Constructor requires a new operator since version 37.

2. Constructor requires a new operator since version 10.

関連リンク

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

 このページの貢献者: chikoski, DriftwoodJP, yasuhiroki, lv7777, akiomik, u_7cc, maruhiro, teoli, Susisu
 最終更新者: chikoski,