Promiseの使い方

<h2>Promise</p2>

<p>Promiseを使うときに、通常にnewしてから使います。<br>
<P>つまり、Promiseはコンストラクターです。では、console.dir(Promise)でPromiseの中身を見てみましょう！</p>

![スクリーンショット 2022-12-21 11.40.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/8eead339-2f61-9ead-a806-b804c27417a6.png)

　Promiseの中にある、resolve, reject, catch, thenメソッドについてまだ分からないと思いますが、順を追って説明いたします。
◉また余談ですが、Promiseは英語で約束の意味があります。一定時間後に必ず結果（result)を返してくるねという風に覚えてればいいと思います。

<h4>まずPromiseの重要な属性、3つの状態から説明いたします。</h4>
 とても大事な内容となるので、ぜひ理解してください。

```javascript
let a1 = new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(1)
  },2000);
})

console.log(a1);
```
consoleから確認できるように、２秒後Promiseの状態（PromiseState属性)がpendingからfullfilledに変わりました。
![スクリーンショット 2022-12-21 12.06.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/616628c5-5502-c5ef-c941-dd7c54abb4cc.png)
![スクリーンショット 2022-12-21 13.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/5f670a1b-6a52-8734-9d68-0845e3a45976.png)

pending, fullfilled, rejectedはそれぞれ下記の意味を表しています。
● <strong>pending: 初期状態
● fullfilled: 処理が成功しました
● rejected: 処理が失敗しました

次に、Promise関数定義の仕方を見ていきましょう。
１のアロー関数の書き方が現在主流になっています。
<h4>Promiseの関数定義</h4>

```javascript
// 書き方1
let a1 = new Promise((resolve, reject)=>{

})

// 書き方2
let a2 = new Promise(function(resolve, reject){

})
```
　resolveとrejectメソッドは引数となります。他の名前にすることもできますが、一般的にそのままresolveとrejectを使うのが普通です。また他のプログラミング言語では、funciton(メソッド）を引数として渡せない場合が多いですが、javascriptができます。これもjavasript言語の魅力の一つです！

 そのために、functionブロックにあるresolve(1)とはresloveメソッドに引数１を渡す意味となります。そして、もう一点覚えてほしいことは、Promiseの状態が一旦変われば、再度変更されることはありません。
<br>
 例えば、pendingからfullfilledにchangeしたら、またrejectの状態に遷移することはありません。
下記の関数では、resolveメソッドが実行されると、rejectメソッドは実行しません。
resove, reject両者の中で一つのみしか実行されません。
```javascript
let a1 = new Promise((resolve, reject)=>{
  resolve();
  reject();  // 実行されません
})

console.log(a1);
```

下記関数の実行結果を見てみましょう。
```javascript
let a1 = new Promise((resolve, reject)=>{
  resolve(1);
  reject();
})

console.log(a1);
```
![スクリーンショット 2022-12-21 13.46.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/9749d8d1-ec58-abbf-fc32-5a01d090e0fd.png)
 結果から分かるように、PromiseResultの結果は１です。では、どのようにすればPromiseResultの値を取得することができるのでしょうか。
答えはthenメソッドとcatchメソッドを使うことです。thenとcatch二つともcallback関数です。
● <strong>resolve関数の処理が成功されると、PromiseResultがthenメソッドに渡されます。
● reject関数の処理が成功されると、PromiseResultがcatchメソッドに渡されます。
```javascript
new Promise((resolve,reject)=>{
  resolve(123)
}).then(res=>console.log(res + '成功したら実行される'))
  .catch(error=>console.log(err + '失敗したら実行される'))
  .finally(()=>console.log('成功や失敗のどちらでも実行される'));
```
また、catchを省略し、下記のように書くこともできます。then関数に二つの引数を渡すという書き方です。
```javascript
new Promise((resolve,reject)=>{
  reject(123)
}).then((res)=>console.log(res + '成功'),
        (err)=>console.log(err + '失敗'));
```

catch, then, resolve, rejectについて紹介はここまでにしたいと思います。次にPromise chainの概念について書きます。
まず前提として分かってほしいのは<strong>.then関数が処理された後の戻り値は新しいPromise対象です。
```javascript
let a1 = new Promise((resolve,reject)=>{
  resolve('123')
});

let a2 = a1.then((res)=>{}); 

console.log(a2);  //undfined
console.log(a1 === a2);  // false
```
処理結果はこんな感じです！
![スクリーンショット 2022-12-21 14.07.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/11cbb1f3-ea68-18f4-3945-743b9b92c9a5.png)
a1.thenの処理結果はundefinedなのに、なんでPromiseStateはfullfilledと疑問に思う方はいると思いますが、原因としては、reject関数が呼ばれていないため、PromiseStateはrejectに変更しません。resove関数について、例え結果はundefinedでもPromiseStateはfullfilledです。

例えば、下記の例だとPromiseStateはrejectになります。
```javascript
let a1 = new Promise((resolve,reject)=>{
  resolve('123')
});

let a2 = a1.then(()=>{  
    let a3 = new Promise((resolve,reject)=>{
      reject()
    })
    return a3
})

console.log(a2);
```
処理結果：
![スクリーンショット 2022-12-21 14.26.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1067004/e0de8f88-ee35-caed-1127-c6da3933d627.png)

では、Promise chainの使い方を見ていきましょう。
```javascript
let a1 = new Promise((resolve, reject)=>{
  resolve(1)
})
let a2 = a1.then((res)=>{
  console.log(res); //1
  return 2
})
let a3 = a2.then((res)=>{
  console.log(res); //2
  return 3
})
let a4 = a3.then((res)=>{
  console.log(res); //3
})
```
もちろん変数名を省略することもできます。
```javascript
let a1 = new Promise((resolve, reject)=>{
  resolve(1)
}).then((res)=>{
  console.log(res); //1
  return 2
}).then((res)=>{
  console.log(res); //2
  return 3
}).then((res)=>{
  console.log(res); //3
})
```

では、Promiseを使うことで、実際にどんな問題が解決できるのでしょうか。
はい、答えはcallbackの無限ループ問題を解決できます。
下記のコードを見ていきましょう。
```javascript
function fn(a){
  setTimeout(()=>{
    console.log(a);
    a--;
    setTimeout(()=>{
      console.log(a);
      a--;
      setTimeout(()=>{
        console.log(a);
        a--;
        setTimeout(()=>{
          console.log(a);
          a--;
          setTimeout(()=>{
            console.log(a);
            a--;
          },1000)
        },1000)
      },1000)
    },1000)
  },1000)
}

fn(6);
```
コードから分かるように、毎回前回処理結果の値を使って新規の処理を行いますが、ソードコードがとても読みづらく、保守性も低いです。
Promiseを使えば、ソースコードは下記に変身できます！
```javascript
function fn(a) {
    new Promise((resolve,reject) =>{
      resolve(a)
    })
    .then((params)=>{
    return new Promise((resolve, reject)=>{
      setTimeout(()=>{console.log(params); resolve(--params)},1000)})
    })  
    .then((params)=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{console.log(params); resolve(--params)},1000)})
    })    
    .then((params)=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{console.log(params); resolve(--params)},1000)})
    })    
    .then((params)=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{console.log(params); resolve(--params)},1000)})
    })    
    .then((params)=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{console.log(params); resolve(--params)},1000)})
    })
  }

fn(6)
```
はい、Promiseを利用すればソースコードの可読性がだいぶ向上しましたね！