JS async/await 非同期関数の整理

2022/09/27に公開

はじめに

現在行っている案件で、よく目にする事になった、async/await。
元々、諸先輩方が書いたコードの為、なんとなく非同期で処理しているんだな、くらいの認識でした。
似たような機能を実装する際は、そこを参考に作って、、という流れだった為、いざ、自分が一から書こうと思った時に、表面的なことしか理解していない事に気づき、よくわからん状態に陥りました。
ここでは、同期/非同期処理の基本から整理して記載していきたいと思います。

よく見ていた記述

async sendMessage() {
const add_data = {
    content: this.inputMessage,
    updatedAt: new Date(),
};
await this.messagesRef.add(add_data)
    .then(() => {
	// console.log('done');
    })
    .catch(function(error: any) {
	console.log("Error getting documents: ", error);
    });
}

業務で行っていたコードを、簡略化したコード。
ここでは、Firebaseのfirestoreにデータを追加する処理を書いてますが、今回とは別のお話の為、詳細は省略。再度用いて説明します。

前提

  • JSは非同期言語である(遅い処理は後回しにされたりする)
  • 非同期関数asyncは、その名の通り非同期で処理が走る
  • async/awaitは、非同期言語であるJSを同期的に処理する

async/awaitを説明する上で、前提として頭に入れておくべきことを記載しました。
というのも、自分自身が、「async/awaitって、非同期処理の何かをしているんでしょ?」という誤った前提のものスタートしてしまった為、途中で、ドユコト?状態に陥ってしまった為です。
上記3つの前提を頭入れた状態で次に進みたいと思います。

async/awaitとは

非同期関数は async キーワードで宣言され、その中で await キーワードを使うことができます。 async および await キーワードを使用することで、プロミスベースの非同期の動作を、プロミスチェーンを明示的に構成する必要なく、よりすっきりとした方法で書くことができます。

mdn_web_docより

曖昧にしていた単語が出てきました。

・非同期関数
・非同期(そもそも
・プロミスベースとの非同期動作

丁寧に見ていきましょう。

非同期関数 asyncとは

非同期で処理される関数です。
例えば、

console.log("あ")

async sendMessage() // "い"を出力する関数とする

console.log("う")

上記の場合、
あ、と出力された後に、
async sendMessage()関数の処理が始まりますが、
その処理結果を待つ前に
う、と出力されます。

これぞ、非同期。順次進行ではなく、プログラムが実行される。

そしてここで疑問。
JSは非同期言語だから、asyncを記載しなくても処理が後回しにされるのではないか?ということ。
結論、されないですが、ここでは、そういうものか、という感じで流していきましょう。

同期処理とは

複数のタスクを実行する際、一つずつ順番にタスクが実行される方式です。
プログラム処理の基本ですね。

同期処理のメリット

プログラムに記載したとおりの順番でタスクが処理されるため、処理全体を把握しやすい。

同期処理のデメリット

プログラムに記載したとおりの順番でタスクが処理されるため、前の処理が終わらないと次の処理にいけない。
つまり、プログラムを実行してから終わるまでの待ち時間が発生してしまいます。

ロケットえんぴつ的に(古い)、一個一個忠実に処理されていきます。

非同期とは

処理の結果を待たずに別の処理を行うこと。

非同期処理のメリット

処理の待ち時間が減る = ユーザーの操作性を向上させることができる
プログラムで待ち時間があるタスクがある場合、その処理を実行しておきながら、別の処理を実行しちゃうため、待ち時間を減らすことができます。
JSはまさにこの非同期処理をベースにした言語です。

いちいち、プログラムの処理を待っていると、その待ち時間が勿体無いですよね。

現実世界で例えるなら、
ハンバーガー屋さんで、前の人が注文して、ハンバーガーを作っている間に、次の人の注文も受け付けることができるよー的なことです。

Promiseとは

Promiseはオブジェクトであり、
非同期処理の完了 (もしくは失敗) の結果およびその結果の値が入っているものです。

Promiseは3つの状態が存在します。

pending: 初期化の状態
resolved/fulfilled: 約束が果たされ、resolve(解決)された状態
rejected: 約束が果たされず、rejected(却下・拒否)された状態

非同期処理の言語を同期的に扱いたい時に使うオブジェクト = Promise

さいごに

基礎の基礎は理解できました。
今度は実際にコードを書いていきながら、まとめていきたいと思います。

Discussion