はじめに
ずっとモヤモヤしていたことがありました。
JavaScriptで処理を“待ちたい”ときにasyncを関数につけますよね。
でもよく考えると、「中身は同期的に処理したいのに、なんで“非同期”って宣言するんだ?」って思てたんですよね。
文系出身の身としてはこの言葉のズレ感がずっと腑に落ちなくて気になってました。
しかも、今回、Springの勉強してたら、@Asyncアノテーションは、「別スレッドで非同期実行する」って意味で使われてるんですよね。
意味が真逆。。。
なんとか、ここを腑に落ちさせる方法はないかなと思って、ChatGPTに聞いたところ、めちゃくちゃ腑に落ちる説明をしてくれたので、まとめておこうと思います。
結論:asyncは「Promiseで結果を返す関数」宣言
ChatGPTさんの言葉を少しアレンジすると、こうなります。
JavaScriptの async = 「この関数は非同期関数です。
“結果”は後で来るかもしれないから、Promiseで返しておくね。」
つまりasyncは、「非同期に処理される」ではなく、「非同期関数として扱われる」という宣言なんですね。
- 関数に
asyncを付けると、戻り値が自動的にPromiseでラップされる - その中で
awaitを使えば、他のPromiseの完了を“待つ”ことができる -
awaitを使わない限りは、Promiseを返すだけで特に「待ち」は発生しない
要するに、
“結果をPromiseで返す関数にする”=“今はまだ非同期関数として扱ってるからね!!!”
という文脈なんです。
なので、関数の中身が同期処理でも非同期処理でも関係なく、
その関数はPromiseを返す関数として扱われます。
Springの@Asyncとの違い
もともとこの話は「Springの@Asyncと意味が真逆では?」という疑問から始まりました。
整理すると、こうなります。
| 言語/フレームワーク | asyncの意味 | 実際の挙動 |
|---|---|---|
| JavaScript | 「この関数の戻り値はPromiseで返す」 =結果が“あとで”来る可能性がある |
関数の呼び出し自体は同期的に始まるが、結果はPromise経由で非同期的に返る |
| Spring(Java) | 「この関数を別スレッドで非同期実行する」 | 呼び出し元とは別スレッドで処理され、FutureやCompletableFutureで結果を受け取る |
要するに、
- JavaScriptの
asyncは「**Promise(値レベル)**の非同期」 - Springの
@Asyncは「**スレッド(実行単位)**の非同期」
という違いがあります。
同じ「async」という単語でも、“どのレイヤーで非同期になるか”がまったく違うんですね。
まとめ
- JavaScriptの
asyncは「結果がPromiseで返る関数」という宣言 -
awaitを使えば、そのPromiseの完了を待てる - Springの
@Asyncは「関数そのものを別スレッドで非同期実行する」
名前は同じでも、本質は全然違うので、
少しの補足で、かなり理解度合いが異なる事例でした。