この翻訳は不完全です。英語から この記事を翻訳 してください。
Promise
オブジェクトは処理の延期(deferred)と非同期処理のために使われます。Promise
はまだ完了していないが、いずれ完了する処理を表します。
構文
new Promise(executor); new Promise(function(resolve, reject) { ... });
引数
- executor
- 2つの引数
resolve
とreject
を通してほかの関数に処理を渡すを持つ関数。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
メソッドはプロミス値を返すので、連鎖させることができます—この処理はcompositionと呼ばれます。Promise.prototype.catch
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による画像の読み込み
Promise
とXMLHttpRequest
で画像を読み込む別の例は、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 |
関連リンク
- Promises/A+ specification
- Jake Archibald: JavaScript Promises: There and Back Again
- Domenic Denicola: Callbacks, Promises, and Coroutines – Asynchronous Programming Patterns in JavaScript
- Matt Greer: JavaScript Promises ... In Wicked Detail
- Forbes Lindesay: promisejs.org
- Nolan Lawson: We have a problem with promises — Common mistakes with promises
- Promise polyfill
- Udacity: JavaScript Promises