10
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

async/awaitを利用したコードの実行順序を把握したい!

Last updated at Posted at 2025-01-28

はじめまして!!ノベルワークス2年目、駆け出しエンジニアのそうまです!!

今回は async/await を利用したコードの実行順序について整理しました!

調査理由

async/await を使って呼び出した関数内でもさらに async/await を使用している場合、コードの実行順序を頭で整理出来なくなってしまったため、今一度纏めようと思いました!!

パターン1

呼び出した関数内で async/await を使用しなかった場合。

以下サンプルコードです。

sample.ts
const getSampleData = async(type: "users" | "comments") => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/${type}`)
    return await response.json();
}

const request = async() => {
    // データ取得が完了したら、ログを出力
    getSampleData("users").then(() => {
        console.log("ユーザーデータ取得完了")
    })
    // データ取得が完了したら、ログを出力
    getSampleData("comments").then(() => {
        console.log("コメントデータ取得完了")
    })
}

const run = async() => {
    await request()
    console.log("通過")
}

run()

この場合ログの出力順はどうなるでしょうか?

僕は「run 関数内で await を使用しているんだし "通過" のログが一番最後に出る筈」だと思ってしまってました...。

しかし実際には以下のような順番になります!

  1. "通過" のログ出力
  2. "ユーザーデータ取得完了"のログ出力
  3. "コメントデータ取得完了"のログ出力

当たり前っちゃ当たり前なんですが...確かに run 関数内で await を使用して request 関数を呼び出してはいますが、request 関数内の処理はレスポンスを待ちません。(正確には json のパース)

つまり、request 関数内の getSampleData の返す Promisepending(待機中) の状態で、request 関数の返す Promisefulfilled(履行済み) になってしまうので "通過" のログ出力が先に実行されると解釈しています!

パターン2

呼び出した関数内で 一部 async/await を使用した場合。

以下サンプルコードです。
(request 関数の最初の getSampleData の呼び出しに await を付けました)

sample.ts
const getSampleData = async(type: "users" | "comments") => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/${type}`)
    return await response.json();
}

const request = async() => {
    // データ取得が完了したら、ログを出力
    await getSampleData("users").then(() => {
        console.log("ユーザーデータ取得完了")
    })
    // データ取得が完了したら、ログを出力
    getSampleData("comments").then(() => {
        console.log("コメントデータ取得完了")
    })
}

const run = async() => {
    await request()
    console.log("通過")
}

run()

この場合はどうなるでしょうか?

...そうですね!request 関数は最初の getSampleData 関数のレスポンスを待つので以下のような実行順になります!

  1. "ユーザーデータ取得完了"のログ出力
  2. "通過" のログ出力
  3. "コメントデータ取得完了"のログ出力

パターン3

今ままでを踏まえて、以下のようなコードの時実行順はどうなるか考えてみましょう。

sample.ts
const getSampleData = async(type: "users" | "comments" | "posts") => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/${type}`)
    return await response.json();
}

const request = async() => {
    await getSampleData("users").then(() => {
        console.log("ユーザーデータ取得完了")
    })
    await getSampleData("comments").then(() => {
        console.log("コメントデータ取得完了")
    })
}

const postRequest = async() => {
    await getSampleData("posts").then(() => {
        console.log("ポスト完了")
    })
}

const run = async() => {
    postRequest()
    request()
}

run()

この場合は request 関数内の処理はコードの記載順に実行されますが、postRequest 内の処理と request 関数内の処理は並列実行となります。つまり、"ユーザーデータ取得完了"ログ"コメントデータ取得完了"ログ は順番通りに出力されますが、"ポスト完了"ログ だけはどこで出力されるかわからない状態となります!!

頭整理.drawio (13).png

纏め

なんとなくasync/await を用いた非同期処理の実行順について理解を深められたかなと思います!

ただ、以下でも書いたんですが、やはり javascript で書いたコードがブラウザでどういう仕組みで動いているのかを理解したいので、次回こそは「イベントループ」や「マイクロタスク」あたりの調査を進めていきたいです!

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?