--- title: Promise slug: Web/JavaScript/Reference/Global_Objects/Promise tags: - クラス - ECMAScript 2015 - JavaScript - Promise - Reference - promise.all - Polyfill browser-compat: javascript.builtins.Promise translation_of: Web/JavaScript/Reference/Global_Objects/Promise --- {{JSRef}} **`Promise`** オブジェクトは、非同期処理の完了 (もしくは失敗) の結果およびその結果の値を表します。 {{AvailableInWorkers}} プロミスの挙動と使用法について学ぶには、最初に[プロミスの使用](/ja/docs/Web/JavaScript/Guide/Using_promises)をお読みください。 ## 解説 プロミス (**`Promise`**) は、作成された時点では分からなくてもよい値へのプロキシーです。非同期のアクションの成功値または失敗理由にハンドラーを結びつけることができます。これにより、非同期メソッドは結果の値を返す代わりに、未来のある時点で値を提供する*プロミス*を返すことで、同期メソッドと同じように値を返すことができるようになります。 `Promise` の状態は以下のいずれかとなります。 - 待機 (_pending_): 初期状態。成功も失敗もしていません。 - 履行 (_fulfilled_): 処理が成功して完了したことを意味します。 - 拒否 (_rejected_): 処理が失敗したことを意味します。 待機状態のプロミスは、何らかの値を持つ履行 (_fulfilled_) 状態、もしくは何らかの理由 (エラー) を持つ拒否 (_rejected_) 状態のいずれかに変わります。そのどちらとなっても、`then` メソッドによって関連付けられたハンドラーが呼び出されます。対応するハンドラーが割り当てられたとき、既にプロミスが履行または拒否状態になっていても、そのハンドラーは呼び出されます。よって、非同期処理とその関連付けられたハンドラーとの競合は発生しません。 `{{JSxRef("Promise.then", "Promise.prototype.then()")}}` メソッドと `{{JSxRef("Promise.catch", "Promise.prototype.catch()")}}` メソッドもまたプロミスを返すので、これらを連鎖 (chain) させることができます。 ![](promises.png) > **Note:** Scheme に代表される一部の言語では、遅延評価や計算を延期する機構を持っており、これらも「プロミス」と呼ばれます。 JavaScript におけるプロミスは、すでに起きつつある処理を表し、この処理はコールバックを使うことで連鎖させることができます。式を遅延評価する方法を探しているのであれば、引数なしのアロー関数を検討してください。 `f = () => expression` で遅延評価される式が作成でき、 `f()` を実行することで評価を実行することができます。 > **Note:** プロミスは履行状態または拒否状態になった場合は、待機ではなく決定 (_settled_) と呼ばれます。また解決 (_resolved_) という用語も見かけるでしょう。これはプロミスが決定したか、他のプロミスの状態に一致させるために「ロックイン」したことを表します。 [States and fates](https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md) には、プロミスの用語についての詳細説明があります。 ### 複数のプロミスの連鎖 `promise.then()`, `promise.catch()`, `promise.finally()` の各メソッドは、決定したプロミスにさらなるアクションを結びつけるために使用します。 `.then()` メソッドは、最大で 2 つの引数を取ります。1 番目の引数は、プロミスが解決した場合のコールバック関数で、 2 番目の引数は、拒否された場合のコールバック関数です。それぞれの `.then()` は新たに生成されたプロミスオブジェクトを返します。このオブジェクトは、オプションで連鎖に使用することができます。例えば、このようになります。 ```js const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('foo'); }, 300); }); myPromise .then(handleResolvedA, handleRejectedA) .then(handleResolvedB, handleRejectedB) .then(handleResolvedC, handleRejectedC); ``` `.then()` に Promise オブジェクトを返すコールバック関数がない場合でも、連鎖の次のリンクへと処理が進みます。したがって、連鎖では最後の `.catch()` まで、すべての*拒否*のコールバック関数を省略しても安全です。 それぞれの `.then()` で拒否されたプロミスを扱うと、プロミスの連鎖のさらに先に影響を及ぼします。エラーを直ちに処理しなければならないため、選択の余地がない場合もあります。このような場合には、連鎖的にエラー状態を維持するために、何らかの種類のエラーを発生させる必要があります。一方で、緊急の必要性がない場合は、最後の `.catch()` ステートメントまでエラー処理を行わない方がシンプルです。 `.catch()` は、実際には、単なる `.then()` からプロミスが解決されたときのためのコールバック関数のスロットを抜いたものです。 ```js myPromise .then(handleResolvedA) .then(handleResolvedB) .then(handleResolvedC) .catch(handleRejectedAny); ``` {{JSxRef("Functions/Arrow_functions", "アロー関数式", "", 1)}}をコールバック関数に使用すると、プロミス連鎖の実装は次のようになるでしょう。 ```js promise1 .then(value => { return value + ' and bar'; }) .then(value => { return value + ' and bar again'; }) .then(value => { return value + ' and again'; }) .then(value => { return value + ' and again'; }) .then(value => { console.log(value) }) .catch(err => { console.log(err) }); ``` プロミスの終了条件は、その連鎖内の次のプロミスの「決定」状態を決定します。解決」状態はプロミスの完了が成功したことを示し、「拒否」状態は成功しなかったことを示します。連鎖内で解決されたそれぞれのプロミスの返値は、次の `.then()` に渡され、拒否された理由は連鎖内の次の拒否ハンドラー関数に渡されます。 連鎖のプロミスは、ロシア人形のように入れ子になっていますが、スタックの一番上のように取り出されます。連鎖の最初のプロミスは最も深くネストされており、最初に取り出されます。 ```plain (promise D, (promise C, (promise B, (promise A) ) ) ) ``` `nextValue` がプロミスである場合、その効果は動的な置換です。 `return` によってプロミスが取り出されますが、 `nextValue` のプロミスはその場所に押し込まれます。上に示した入れ子では、"promise B" に関連付けられた `.then()` が "promise X" の `nextValue` を返すとします。 結果としての入れ子は以下のようになります。 ```plain (promise D, (promise C, (promise X) ) ) ``` プロミスは複数の入れ子に参加することができます。以下のコードでは、 `promiseA` が「決定」状態に移行すると、 `.then()` の両方のインスタンスが呼び出されます。 ```js const promiseA = new Promise(myExecutorFunc); const promiseB = promiseA.then(handleFulfilled1, handleRejected1); const promiseC = promiseA.then(handleFulfilled2, handleRejected2); ``` 既に「決定」状態のプロミスにアクションを割り当てることができます。その場合、アクションは (適切であれば) 最初の非同期の機会に実行されます。プロミスは非同期であることが保証されていることに注意してください。したがって、既に「解決」状態のプロミスに対するアクションは、スタックがクリアされ、クロックティックが経過した後にのみ実行されます。この効果は `setTimeout(action,10)` とよく似ています ```js const promiseA = new Promise( (resolutionFunc,rejectionFunc) => { resolutionFunc(777); }); // この時点で、 "promiseA" はすでに解決されています。 promiseA.then( (val) => console.log("asynchronous logging has val:",val) ); console.log("immediate logging"); // 以下の順序で出力が行われます。 // immediate logging // asynchronous logging has val: 777 ``` ### 現行の設定オブジェクトの追跡 設定オブジェクト (settings object) とは、 JavaScript コードの実行時に追加情報を提供する[環境](https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object)のことです。これには、領域やモジュールマップのほか、オリジンなどの HTML 固有の情報も含まれます。現行の設定オブジェクトが追跡されるのは、特定のユーザーコードに対してどの設定オブジェクトを使用すべきかをブラウザーが確実に把握するためです。 これをより良く理解するために、領域がどのように問題になるかを詳しく見てみましょう。領域 (**realm**) とは、大まかに言うとグローバルオブジェクトのことです。領域の特徴は、JavaScript のコードを実行するために必要な情報をすべて保持していることです。これには [`Array`](/ja/docs/Web/JavaScript/Reference/Global_Objects/Array) や [`Error`](/ja/docs/Web/JavaScript/Reference/Global_Objects/Error) などのオブジェクトが含まれます。それぞれの設定オブジェクトはこれらの「コピー」を持っており、共有されていません。そのため、プロミスとの関係で予期しない動作をすることがあります。これを回避するために、**現行の設定オブジェクト** (incumbent settings object) と呼ばれるものを追跡します。これは、ある関数呼び出しを担当するユーザーコードのコンテキストに固有の情報を表します。 これをもう少し詳しく説明するために、文書に埋め込まれた [` ``` 同じ概念をプロミスに適用します。上の例を少し変えてみると、こうなります。 ```html ``` これを変更して、文書内の ` ``` ```html ``` 上記の例では、現行の設定オブジェクトが追跡されたときのみ `