Promise の基礎知識

**2023/09/15 更新**

Callbackは嫌だが、Promiseもなかなか馴染めない。async/awiatでいいじゃないか。しかしもう一度だけPromiseを振り返ってみたい。備忘録的なまとめです。

[Promise Executor の例外 - Qiita](https://qiita.com/sand/items/c2f001f0bef3e02b3c31)
[ES6のPromiseの基本を考えてみた - Qiita](https://qiita.com/sand/items/5360bc03390f89a7ceb3)


async/awaitのわかりやすい説明です(2019/07/15追加)
[async/await 入門（JavaScript）](https://qiita.com/soarflat/items/1a9613e023200bbebcb3)



# １．Promise ライフサイクル

Promiseは非同期処理の結果を保持するプレースホルダ（オブジェクト）です。promiseは短いライフサイクルを持ちます。Pending stateでスタートし、Fulfilled state またはRejected state で終了します。


* Pending : promiseの非同期処理はまだ終了していない
* Fulfilled : promiseの非同期処理が終了して、成功した
* Rejected : promiseの非同期処理が終了して、失敗した


# ２．Promise Executor と Fulfillment handler


::: note info
**Promise Executorについて**
**Promise Executor**とは、Promiseオブジェクトを作成するときに渡す**コールバック関数**のことです。Promise Executorは、非同期処理の結果をPromiseオブジェクトに反映するための関数です。Promise Executorは、**resolve** と **reject** という2つの引数を受け取ります2。resolveは非同期処理が成功したときに呼び出す関数で、引数に非同期処理の結果を渡します。rejectは非同期処理が失敗したときに呼び出す関数で、引数にエラー情報を渡します。Promise Executorは、Promiseオブジェクトの状態を**pending（未解決）**、**fulfilled（解決済み）**、**rejected（拒否）** のいずれかに変更することができます。
**Fulfillment handler** はthenメッソドの第1引数に渡される関数です。**Rejection handler** はthenメソッドの第2引数またはcatchメッソドの第1引数に渡される関数です。
:::


以下はPromise Executor と Fulfillment handlerを説明するための短いコードです。

```javascript:
let promise = new Promise(function(resolve, reject) { // (1) Promise Executor
    console.log("Promise Executor");
    resolve(); // (3) Fulfilled stateになる
});

promise.then(function() {  // (2) Fulfillment handler
    console.log("Fulfillment handler");
});

console.log("最後の実行");
```


以下はPromise ExecutorとFulfillment handlerの説明です。

* **Promise Executor** : Promise()コンストラクタの引数関数（非同期処理）。
* **Fulfillment handler** :  then()の引数関数。


以下はPromise ExecutorとFulfillment handlerの実行タイミングの説明です。

* **Promise Executor はすぐに実行されます。** （new Promise(...) call時）
* **Promise Executorの中で(3)のresolve()が呼ばれると、(2)のFulfillment handlerがjob queueの最後に追加されます。つまりhandlerは非同期処理になります。**


つまりこのコードの実行結果は以下のようになります。Fulfillment handlerが一番最後に実行されます。

```
Promise Executor
最後の実行
Fulfillment handler
```


繰り返しになるので省きますが、**Fulfilled handlerと全く同じことがRejected handlerについて言えます。**


# ３．promise.then()はpromiseを返す

promise.then()はpromiseを返します。ですからpromise.then().then()...then()のようにチェインで連鎖させることができます。


```javascript
let p1 = new Promise(function(resolve, reject) {
    resolve("スタート");
});

p1.then(function(value) {
    console.log(value);
}).then(function() {
    console.log("終了");
});
```

実行結果は以下の通りです。

```
スタート
終了
```


# ４．Fulfilled handler が通常の値をreturnする場合

以下はFulfilled handlerが通常の値をreturnし、次のFulfilled handlerで受け取る例です。

```javascript
let p1 = new Promise(function(resolve, reject) {
    resolve(1);
});

p1.then(function(value) {
    console.log(value);         // "1"
    return value + 1;
}).then(function(value) {
    console.log(value);         // "2"
});
```


# ５．Fulfilled handler が promise をreturnする場合

以下は **Fulfilled handlerがpromiseをreturnし、次のFulfilled handlerでそのpromiseのresolve値を受け取る** 例です。**もしp2がresolve(2)ではなくreject(2)を実行していたら、2番目のFulfillment handlerは呼ばれないことに注意してください。** この場合は、then()でなくcatch()で、Rejected handlerを定義しておけば、それが呼ばれることになります。

```javascript
let p1 = new Promise(function(resolve, reject) {
    resolve(1);
});

let p2 = new Promise(function(resolve, reject) {
    resolve(2);
    // reject(2)
});

p1.then(function(value) {
    // 最初のfulfillment handler
    console.log(value);     // 1
    return p2;
}).then(function(value) {
    // 2番目のfulfillment handler
    console.log(value);     // 2
});
```


今回は以上です。