WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

JavaScript の async / await

by WebSurfer 2022年11月25日 18:50

JavaScript の async / await の使い方について思い違いをしていました。また同じミスを犯さないように、どういうことだったかを以下に書いておきます。

例として、GET 要求を受けると 2 秒後に以下の JSON 文字列を返す Web API から fetch を使って応答を取得するサンプルを書きました。

{"id":5,"name":"スライムマン"}

JavaScript のコードは以下のようにし、ボタンクリックなどのイベントで asyncTest を実行します。

const fetchHero5 = async () => {
    const response = await fetch("/api/values/5")
    const data = await response.json();
    console.log(data.name);
};

const writeLog = () => {
    console.log("writeLog の実行");
}

// 同期的に順番に実行される
function asyncTest()
{
    fetchHero5();
    writeLog();
}

fetchHero5 の中で await で待機しているので、asyncTest の中の fetchHero5 の呼び出しでまず Web API からの応答の "スライムマン" がコンソールに書き込まれ、その後 writeLog が呼び出されて "writeLog の実行" が書き込まれると思っていたのですが、そうではなかったです。

結果は以下の通りで、思っていたのと逆の順序でした。

コンソール書き込み

asyncTest は同期関数でその中の fetchHero5() と writeLog() は同期的に実行されます。つまり、同期的に順番にまず fetchHero5 が呼ばれ、fetchHero5 の完了後 writeLog が呼ばれるという動きになります。

ここで、fetchHero5 は async が付与された非同期関数であるということが、自分が思っていた結果と違ったことになった原因のようです。

現代の JavaScript チュートリアル の記事 Async/await に "async は関数が promise を返すことを保証し、非 promise をその中にラップします" という説明があります。

ということは、fetchHero5 が呼ばれると即 Promise が返され、その時点で fetchHero5 は完了とみなされて、次の writeLog が呼ばれてコンソールに "writeLog の実行" と書き込んだということのようです。

その後、Web API からの応答の処理は fetchHero5 から返された Promise が行うようです。Promise オブジェクトが fetch で Web API を呼んで 2 秒後に応答が返ってきてから "スライムマン" と書き込んだということだと思います。

fetchHero5() で "スライムマン" と書き込んだ後で、writeLog() で "writeLog の実行" と書き込む(上の画像の順序を反対にする)には、asyncTest に async を付与してを非同期関数にし、その中の fetchHero5 に await を付与してそこで待機するようにします。

すなわち以下のようなコードにします。

async function asyncTest()
{
    await fetchHero5();
    writeLog();
}

結果は以下の通りとなります。

コンソール書き込み

上のコード例で、一番下位の関数 fetch, json は Promise を返します。その上位の関数 fetchHero5 も async が付与されているので Promise を返します。そういう形で Promise が下位から上位に伝搬して行くので、上のコード例でのように最上位の関数 asyncTest を非同期にして、そこで await を使って fetchHero5 の完了を待機すると期待したようになるということのようです。

.NET アプリの Microsoft のドキュメント「非同期プログラミングのベスト プラクティス」には "上から下に (または下から上に) 非同期コードが他の非同期コードを呼び出す、または呼び出される場合に最もうまく機能する" ということがに書かれています。

それは JavaScript でも同じことなのかもしれません。

(自分用のメモ: 検証に使ったのは VS2022 の MvcCore6App2 プロジェクトの Home/Api)

Tags: , , ,

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係���記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar