鶏(async)と卵(await)、どちらが先か？

「[[JS]なぜawaitはasync関数の中にしか書けないのか](https://qiita.com/jun1s/items/ecf6965398e00b246249)」の記事の補足というか、おまけ記事です。


#鶏と卵

多くの人は、「awaitを使いたい」がまず先にあると思います。

```javascript
const data = await doAjax();
```

上記の書き方に「これは便利そうだぞ？」とビビッとくるわけです。

しかしその後、次のルールを知って「ん？ なんかめんどくさそうだな？」となります。

:::note warn
awaitの先は、Promiseを返す関数か、async関数でなくてはならない
:::

Promiseを返す関数というのはつまりこういうことです。

```javascript
function sleep(seconds) {
	return new Promise(resolve => 
		setTimeout(() => resolve(), seconds * 1000)
	);	
}
```

このsleep関数をこんな風に使えます。awaitはasync関数の中でしか使えないので、わざわざasyncな無名関数を定義して即時呼び出ししています。

```javascript
(async () => {
  console.log("start");
  await sleep(2);
  console.log("hello");

})();
```


そして「なるほど、awaitは、戻ってくるPromiseの解決を待ってくれるわけか」と理解します。
しかし、次に「もうひとつの、"async関数"ってなんだ？」となるはずです。

そしてasync関数について調べると、次のことが分かります。

:::note info
async関数は、関数の返り値をPromise.resolve()で包みます。
:::

「どういうこと？」という感じです。
例えば、"hello"と返すだけの関数があったとします。

```javascript
function hello(){
	return "hello";
}

const msg = hello();
console.log(msg);
```

出力

```
hello
```

このhello関数の戻り値を、Promise.resolve()で包んでみます。
resolveされたPromiseが返るので、thenで受けなくてはなりません。

```javascript
function test(){
	return Promise.resolve("hello");
}

test().then((msg)=>{ 
	console.log(msg) 
});
```

出力

```
hello
```

これを自動的にやってくれるのがasync関数だ、ということです。

```javascript
async function test(){
	return "hello";
}

test().then((msg)=>{ 
	console.log(msg) 
});
```

「なるほど。それで、それは何のためにそうするんだ？ awaitからはこの関数しか呼び出せないというのはどういうことだ？」という感じですが、asyncの中でawaitを使うと意味がわかってきます。

```javascript
async function test(){
	const msg = await getMessageAsync();
	return msg;
}

test().then((msg)=>{ 
	console.log(msg) 
});
```

getMessageAsync()は、内部でサーバにメッセージを問い合わせる非同期関数です。呼び出すとPromiseを返し、サーバからの問い合わせが返った時にそのPromiseを完了状態にします。

```return msg```が実行されるのは```await getMessageAsync()```のPromiseが完了になった後ですから、それまでは、test()が返すPromiseは待機状態のままです。そして、getMessageAsync()が完了になった後、```return msg```が、Promiseを完了状態にしてmsgを渡します。

こういった、本来ややこしいPromiseの管理を、asyncとawaitが肩代わりしてくれるわけですが、ここで重要なのは、「**awaitがなければasyncにはほぼ意味がない**」ということです。

言い換えると、**awaitを中で呼び出す為のasync関数であって、async関数を呼び出す為のawaitではない**ということになるでしょう。

この理解の前に「awaitで呼び出せるのはasync関数」と聞くと、まるで「asyncが先にあって、それを扱う為のawait」のように錯覚してしまいますが、そうではなく、awaitはあくまでもPromiseを同期的な書き方で扱うためのものです。そしてawaitを適切に処理する為に、asyncが存在します。

async関数はPromiseを返すので、結果的にawaitはasync関数も扱える、というだけですね。非常に便利な仕組みだと思います。

ちなみに、何も返さない関数をasyncにしたらどうなるかというと、ちゃんとPromise.resolve()が返ります。

```javascript
async function test(){
}

test().then((msg)=>{ 
	console.log("done!") 
});
```

なので、次のようにawaitを次々と呼び出すような場合も、単にそのまま処理を終わればOKです。

```javascript
async function test(){
	const data1 = await longProcAsync1();
	const data2 = await longProcAsync2(data1);
	const data3 = await longProcAsync3(data2);
	await lastProcAsync(data3);
}

test().then((msg)=>{ 
	console.log("done!") 
});
```

というわけで、長くなりましたが、結論は以下の通りです。

:::note info
鶏(async)と卵(await)は、卵(await)が先である。
:::

awaitがやりたいからのasync、ということでした。

#おまけ：asyncとは結局何か
最初にasyncについてこう書きました。

:::note info
async関数は、関数の返り値をPromise.resolve()で包みます。
:::

しかし、前回の記事を読めばわかるように、実際はそれだけでは全然なくて、

:::note info
asyncは、それを付けた関数をawaitからawaitまでのブロックで分割したジェネレータに変換し、各awaitが待つPromiseが完了状態になった時に次のブロックへと処理を進め、関数が終了した時に結果をPromise.resolve()で包んで返します。
:::

ということでした。async、すごいやつです。

#おまけ２：なぜawaitを最上位コードに書けないのか？

（追記 2021/07/21）なんと、もうすぐ最上位にawaitを書けるようになるかもしれないそうです（一部ブラウザは実装済）。コメント欄で教えて頂きました。感謝！

ちなみに、そろそろasync/awaitにも慣れてきて、次のように書きたくなってきたかもしれません。

```javascript
async function test(){
	const msg = await getMessageAsync();
	return msg;
}

const msg = await test();
console.log("done")
```

しかしこれはエラーになって実行できません。なぜならjavascriptコンパイラは、async関数に入っていない```await test()```をジェネレータに変換できない為です（最上位のコード全体をまとめて1つのジェネレータに変換すれば可能かもしれませんが、さすがにそれはやりすぎということでしょう）。

これなら大丈夫です。

```javascript
async function test(){
	const msg = await getMessageAsync();
	return msg;
}

async function main(){
	const msg = await test();
	console.log("done")
}

main();
```