【JavaScript】非同期処理とasync/await ~難しいこと抜きで、まず使いはじめるための知識~ ( ´ε` )💻

#この記事について
この記事は、非同期処理のことをほとんど知らなかった方や、
async/awaitを使ったコードをとりあえず書いてみて覚えたいという方のために、
使用上問題ないレベルで理解してもらえるよう、カンタンに説明させていただきたいと思います。

コードを読むときに「何をしたいのかわかる」
コードを書くときに「とりあえず使ってみる」
程度のレベルまで理解していただければOKという、ゆるい説明になります。
正しい知識を追求したい場合は、各自で行っていただければと思います。
（そして共有してください♡）

ちなみに、async/awaitを使わない非同期処理の書き方については、あまり知見がありません。
（自分がプログラミングを学び始める時点で、すでにasync/awaitが誕生していたため。）
予めご承知おきください。

#非同期処理とは「上から順番に実行されるわけではない処理」のことです。
JavaScriptのコードは基本的に上から順番に実行されます。
しかしJavaScriptの中には一部、このルールを無視する処理が存在します！
この「上から順番に実行されるわけではない処理」を「非同期処理」と呼びます。


#非同期処理を行う関数は、主に２種類あります。

JavaScriptで非同期な処理を行う関数は、主に以下の２種類です。

1. **タイマー処理**（`setTimeout()`や`setInterval()`など。）
2. **HTTP通信を行う処理** …つまり**Ajax**
（`fetch()`や`$ajax()`、`axios()`など。）

<details><summary>「HTTP通信を行う」というイメージがよくわからない方への説明</summary>
<div>
JavaScriptには、
**他のURLにアクセスし、そのURLが配信しているデータを取得してくる**ための関数があります。
これを技術的に言うと、JavaScriptで**HTTP通信を行う**ための関数ということになります。
（JavaScript上でAPIを実行する時などに必要になってくる機能です。）
そして、このJavaScriptでHTTP通信を行う処理のことを、**Ajax**と呼びます。
</div>
</deteils>

非同期の処理は、処理の完了を待たずに、次の処理の実行が開始されます。
（なんのためにそんなことをするかというと、この処理の実行中に、他の処理も全て止まってしまうような事態を防止するためかと思います！）

```JavaScript:（例）
/* 通常の処理は、前の処理の実行が完了してから、次の処理が実行される。 */

console.log(1); 

console.log(2);
// ↑ consoleに 1 と表示されてから実行される。

setTimeout( function(){console.log(3)}, 0 );
// ↑ consoleに 2 と表示されてから実行される。

console.log(4);
// ↑ 前の処理が非同期なので、consoleに 3 と表示されているか否かに関わらず、実行される。

```

#async/awaitは、非同期処理の完了を待つための方法です。

上述の処理は非同期処理であると言いましたが、
`setTimeout()`はともかく、HTTP通信を行う処理の場合、
返り値が返ってくるまえに次の処理が実行されちゃったら、意味がありません！

そのため、非同期処理の完了を待ってから処理を続行するための方法が生まれました。
その方法の中で、最も新しい方法がasync/awaitなのです。

つまり「非同期処理を、通常の同期処理のように実行させる仕組み」ということです。

#async/awaitが現れる前から、そのためのやり方は存在していました。

非同期処理を通常の同期処理のように実行させる仕組みには歴史があり、下記のように変遷してきました。

（過去）　*コールバック処理* → `Promise` → `async/await`　（現在）

ざっくり説明すると、

####*コールバック処理*
関数の引数に関数を渡すことで、
「最初の処理がおわったら、次の処理を実行するよ」と指定する方法です。
（最近では主にタイマー関数のみで使われる方法かと思います。）

```JavaScript
setTimeout( 次の処理, 100 );
```

####`Promise`

「処理が完了したかどうか」を判別することができる型のことです。
Promiseというのはクラスの名前ですので、利用する際はインスタンスを生成します。

```JavaScript
const インスタンス = new Promise( 本来実行したい関数 );
```

Promiseインスタンスは、関数と同じように`インスタンス()`と実行すると、
`本来実行したい関数`の実行が開始されます。
そして、返り値には**「処理が完了したかどうか」を判別できるデータ**が返されます。
（`本来実行したい関数`の中で`return`されていた値は、そのデータの内部に格納されます。）

このデータのおかげで、JavaScriptは非同期処理を柔軟に扱えるようになりました。
**この記事では今後、このデータの事を *Promise* と呼びます。**

（ *Promise* に対してメソッドチェーンを使っていくことで、完了後に行う処理を指定できるという仕組みですが、この記事では解説しません。）

####`async/await`
*Promise* をそのまま扱うよりも、もっとシンプルにコードが書けるように`async/await`が登場しました。
この書き方が登場したことにより、今まで以上にシンプルに非同期処理を扱うことができるようになりました。

なので`async/await`は、完了状態を判別するための新しい機能というわけではなく、
「 *Promise* を使う処理は書き方がめんどくさかったから、もっと簡単に書けるようにした」
というようなものです。
完了状態を判断する際には、結局 *Promise* （＝「処理が完了したかどうか」を判別できるデータ）を利用しています。

#async/awaitの使い方

`async`と`await`。
この２つのうち、主役となるのは`await`ですので、`await`の使い方から説明していきます。

今後の説明では、非同期処理を行う関数の存在が必要となるので、
例として、非同期処理を行う `API()` という関数があるものとします。

<details>
<summary>補足</summary>
<div>

通常は、非同期処理を行う関数は、引数がもうすこし複雑な記述になります。

**Ajax関数の場合**
たとえば、Ajaxを実行するための`fetch` `$ajax` `axios` 、
または 他社のAPIを実行するために作成されているオリジナルの関数の場合、
引数に *接続先の情報や、接続先に渡したい情報などを含んだオブジェクト* を渡すような書き方になります。
**タイマー関数の場合**
また、Vue.js の `this.$nextTick` 等をはじめとする タイマー関数 の場合、
引数に *時間経過後に実行したい処理（関数）* を渡すような書き方になります。

今回使用する `API()` は、
*それらの情報を既に内部で定義してあるラッパー関数* だと想定していただければ幸いです。
（通常のコードを記述する場合も、
　今回のようにラッパー関数を作成しておくか、
　もしくは引数に渡す情報を前もって変数に定義するなりして、
　すっきりしたコードで記述することをオススメします。）
</div>
</details>


####`await`の使い方

`await`演算子は、非同期処理の関数を実行するときに使用します。
`await`演算子を付加して実行された関数は、
処理がおわるまで次に進まないよう、待っていてくれます。


```JavaScript:（例）
await API();
// ↑ await を付けない場合、処理が完了するより先に下の行の処理が実行される。

console.log('処理が完了しました。');
// ↑ await を付けたため、 API() の処理がおわってから実行される。
```

####`async`の使い方

`async`装飾子は、関数を定義するときに使用します。
（`async`装飾子を付けて定義された関数を、便宜上 *async関数* と呼びます。）

じつは`await`演算子を使用できるのは *async関数* の中だけなのです。
なので、*`await`を利用するために仕方なく使う* という認識で問題ありません。
（グローバルスコープで`await`を使えるようにする案も、検討されているとかいないとか…。）

```JavaScript:function文
async function async関数(){
  // await を使う処理は、この中にしか書けない。
}
```
```JavaScript:アロー関数
const async関数 = async ()=>{
  // await を使う処理は、この中にしか書けない。
}
```

関数を *async関数* として定義すると、返り値は *Promise* になります。
つまり、返り値で「処理が完了したかどうか」を判断できるようになります。

####`await`のもうひとつの役割

さきほどから *async関数* の返り値は *Promise* であると言っていますが、
じゃあ *async関数* に設定していた返り値（ *async関数* を定義するときに `return ooo;`と書いて指定していた値）はどうやって取り出すのか？と気になるかと思います。

そこで、`await`のもうひとつの重要な役割がポイントになってきます。
`await` には「 *async関数* が本来返り値にする予定だった値を取り出す」という役割があります。

```JavaScript:（例）
async function async関数(){
  return '本来返り値にしたかったデータ';
}

const awaitをつけないパターン = async関数();
// ↑ 「awaitをつけないパターン」 には Promise が入っている。

const awaitをつけるパターン = await async関数();
// ↑ 「awaitをつけるパターン」 には '本来返り値にしたかったデータ' が入っている。
```

なので、`await`を利用することで、
処理の完了を待つこと＆本来の返り値を取得することが、同時に実行できます。

ちなみに、`await`は  *async関数* の実行時に直接つけなければいけないわけではなく、
 *Promise* に対してであれば使うことが可能です。

なので、一旦`awaitをつけないパターン`で *Promise* を取得しておいて、
実際に返り値を使う必要があるときに`await`で返り値を取り出してあげると、
無駄のないコードが書けます。

```JavaScript:（例）
const awaitをつけないパターン = 時間がかかる関数(); // 例: 大量のデータを取得してくるAPIなど。

// 時間がかかる関数() には await をつけていないため、処理がおわったかどうかに関わらず、次の処理が進んでいく。
// この間に実行しても問題ないような、他の処理を進めておく。

// 時間がかかる関数() の返り値を使う必要があるタイミングで await をつける。
const 時間がかかる関数の返り値 = await awaitをつけないパターン;

// こうすることで 「時間がかかる関数の処理が終わっていない場合だけ、処理が終わるのを待つ」 という流れにできる。

```

#### 複数の非同期処理が完了するのをまとめて待ちたい場合

このような処理をしたい場合のやり方が、過去記事にまとめてありますので、参考にご覧ください。
[３秒で理解する async/await関数 の並列実行](https://qiita.com/H40831/items/c63acffa3dcc1234c8fc)

#おわり
いかがでしょうか？
この記事をお読みいただいた方々が、
なんとなく思ったとおりに`await`を扱えるようになってくれたら幸いです。

記事を書いてる途中に期間をあけすぎてしまったため、内容が中途半端かもしれませんが一旦投稿します。
説明してなかったなっていう事を思い出したら、後日追記したいと思います。

ご拝読ありがとうございました。