JavaScriptの非同期処理について(Promise、async/await)

また自分の理解したことのメモです。

JavaScriptの非同期処理に関して、主に`Promise`と`async`/`await`について理解したことをまとめたいと思います。

##非同期処理
同期処理とは、簡単に説明すると処理が上から順番に行われていくことです。

```javascript:script
console.log(1);
console.log(2);
console.log(3);
```
```text:出力
1
2
3
```
これに対し、非同期処理とは1つの処理が終わるのを待たずに次の処理が行われることです。例として非同期関数である`setTimeout()`を使用してみます。

```javascript:script
console.log(1);
setTimeout(function(){
  console.log(2)
},100);
console.log(3);
```
```text:出力
1
3
2
```
このように`setTimeout()`の処理を待たずにあとの処理が先に行われました。これはサーバーとの通信などで時間のかかる処理によって、プログラム全体が止まってしまわないようにするために使われます。

##`Promise`
`Promise`とは非同期処理の状態を表すオブジェクトです。Promiseには以下の3つの状態があります。
・`pending` : 処理が実行中
・`fulfilled` : 処理が成功
・`rejected`  : 処理が失敗

`Promise`の処理が終了した後に、結果を利用するには`Promise`のメソッドである`then()`と`catch()`を用います。
・`then()` : `Promise`の状態が`fulfilled`のとき実行される処理
・`catch()` : `Promise`の状態が`rejected`のとき実行される処理

以下のような例で具体的に説明します。

```javascript:script
//Promiseオブジェクトを返す関数を定義
function time(sec){
  return new Promise(function(resolve,reject){
    setTimeout(function(){
      //100より小さいと成功(fulfilledの状態を返す)
      if(sec <= 100){
        resolve();
      }
      //それ以上では失敗(rejectedの状態を返す)
      else{
        reject();
      }
    },sec)
  })
};

console.log(1);
time(100)
  .then(function(){console.log('success')})
  .catch(function(){console.log('error')})
time(1000)
  .then(function(){console.log('success')})
  .catch(function(){console.log('error')})
console.log(2);
```
```text:出力
1
2
success
error
```

`Promise`オブジェクトを返す関数として戻り値が`new Promise`となる関数を定義します。`resolve()`,`reject()`はそれぞれ処理が完了した時、失敗したときに呼び出されます。`time(100)`のときは`Promise`の状態が`fulfilled`で返されるため、`then()`の中の処理が行われ、一方、`time(1000)`のときは`Promise`の状態が`rejected`で返されるため、`catch()`の中の処理が行われます。

また、`then()`メソッドは戻り値として`Promise`オブジェクトを返すため、連続して書くことができます。この時途中でエラーが起きると処理が飛ばされ`catch()`が呼び出されます。

```javascript:script
time(100)
  .then(function(){console.log(1)})
  .then(function(){console.log(2)})
  .then(function(){console.log(3)})
  .catch(function(){console.log('error')})
console.log(4)
```
```text:出力
4
1
2
3
```

##`async`/`await`
`async`/`await`を用いた非同期処理の構文について説明します。`async`とは関数の前に宣言することで、非同期関数を定義することができます。

```javascript:script
//非同期関数の宣言
async function sample() {}
```
非同期関数は戻り値として、`Promise`オブジェクトを返します。関数の処理が実行され、値を返すと戻り値を`resolve`が呼び出され、何らかのエラーなどが起こると`reject`が呼び出されます。

`async`で定義した非同期関数の中では`await`という演算子が使用できます。`await`を関数の前に指定すると、その関数の`Promise`オブジェクトが結果を返すまでその後の処理が待機します。

```javascript:script
//awaitを用いない時
async function sample1(){
  time(100)
    .then(function(){console.log(1)})
  console.log(2);
}
//awaitを用いた時
async function sample2(){
  await time(100)
    .then(function(){console.log(1)})
  console.log(2);
}


sample1();
sample2();
```
```text:出力
2
1 
1
2
```

`await`を用いない場合、関数の中の非同期処理より先にあとの処理が実行されますが、`await`を用いると指定した関数の処理が終了するまであとの処理が行われません。

非同期処理を同期的に処理したい場合、`Promise`の`then()`メソッドを用いるよりも、`async`/`await`を用いるほうが簡潔な記述でかけることが多いです。

##まとめ
JavaScriptの非同期処理に関することとして、`Promise`と`async`/`await`についてまとめてみました。`async`/`await`を用いると記述が簡潔になりますが、新しい規格のため対応していないこともあるので注意が必要です。

##参考記事
[【JavaScript】Promise で非同期処理を記述するー株式会社ライトコードー]
(https://rightcode.co.jp/blog/information-technology/javascript-promise)
[JavaScriptと非同期処理の話](https://qiita.com/KuwaK/items/7e31f8b0ef26718c82ea)
[async/await 入門（JavaScript）]
(https://qiita.com/soarflat/items/1a9613e023200bbebcb3#resolve%E3%81%99%E3%82%8B)