この翻訳は不完全です。英語から この記事を翻訳 してください。

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と呼ばれます。

Not to be confused with: いくつかのほかの言語では遅延実行のメカニズムを持っていたり、計算を延期する機構を持っており、それらはまた、"Promise"と呼ばれます。例えばSchemeなどです。Promises in JavaScript represent processes which are already happening, which can be chained with callback functions. If you are looking to lazily evaluate an expression, consider the arrow function with no arguments: f = () => expression to create the lazily-evaluated expression, and f() to evaluate.

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)
プロミスに成功ハンドラと失敗ハンドラを付加します。呼ばれたハンドラの戻り値によって解決している新しいプロミスを返します。

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 && 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 の定義
ドラフト  

ブラウザ互換性

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 32.0 29.0 (29.0) 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) 未サポート 未サポート 8 32.0

関連リンク

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

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