[JavaScript] 僕がasync/awaitを好きなワケ

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おばんです、iOSDCの賞品であるtv 4kがちょうど手元に届いた田中です。しっかり開発して遊ぼうと思います。(オススメの4kディスプレイ情報お待ちしています)

さて、非同期処理周りのコードを簡潔に書きたいという気持ちから、業界的にPromiseが親しまれて久しい今日この頃。みなさまasync/awaitの方は使っておりますでしょうか。僕はちょうど最近触る機会があったので、今回はasync/awaitを使うと何が良いのか、これまであったPromiseと比較しながら紹介していこうと思います。

ネストが浅くなる

以下のコードを見比べてください。非同期処理ではなく、単純なサンプルですがPromiseの方はPromiseオブジェクトを生成してその中でresolveとrejectを返す必要があるため、一段ネストが深くなっています。async/awaitではそうなっていません。

ネストが浅いとコードは読みやすくなります。僕がasync/awaitを好む一つ目の理由がこれです。

Promise

const promiseFunction = () => {
    return new Promise((resolve, reject) => {
        resolve('hoge')
    })
}

async/await

const asyncAwaitFunction = async () => {
    return await 'hoge'
}

(見かけ上)Promiseオブジェクトのやりとりがなくなる

Promiseで非同期の関数を繋げて扱う場合、それぞれの関数で返却する値はPromiseオブジェクトにしなければいけないため、毎度 return new Promise() しなければならなくなります。(前述した通り、この書き方をするとネストが深くなり、読みやすさが減ります。)

また、成功時の処理は .then で扱う必要があります。コールバック地獄を扱うよりははるかに良くなっていますが、パッと見たときにコードが込み入っている印象を受けるかもしれません。(※個人の感想です。)

以下は非同期処理ではありませんが、Promiseとasync/awaitをシンプルに比較したコードです。

Promise

const promise1 = (num) => {
    return new Promise(resolve => {
        resolve(num + 1)
    })
}

const promise2 = (num) => {
    return new Promise(resolve => {
        resolve(num + 2)
    })
}

const promise3 = (num) => {
    return new Promise(resolve => {
        resolve(num + 3)
    })
}

const promise = promise1(0)
    .then(num => {
        return promise2(num)
    })
    .then(num => {
        return promise3(num)
    })
    .then(num => {
        console.log(num)
    })
    .catch(error => {
        console.log(error)
    })
    
// 6 <- コンソールに出力される

async/await

そのまま変数として扱えるような見た目になります。async functionは暗黙的にPromiseオブジェクトを返却していて、 .then の扱いはそのPromiseオブジェクトの返却した値で解決されるようです。(詳しくはこちら)

const asyncAwait1 = async (num) => {
    return await num + 1
}

const asyncAwait2 = async (num) => {
    return await num + 2
}

const asyncAwait3 = async (num) => {
    return await num + 3
}

const asyncAwait = async () => {
    const aa1 = await asyncAwait1(0)
    const aa2 = await asyncAwait2(aa1)
    const aa3 = await asyncAwait3(aa2)
    const sum = aa3
    console.log(aa3)
}

asyncAwait().catch(error => { console.log(error) })

// 6 <- コンソールに出力される

注意点

async/awaitはES7から採用される機能です。ウェブフレームワークとブラウザがES7に対応しているかどうかを確認しましょう。

まとめ

  • Promiseオブジェクトを明示的に返却する必要がなくなるので、ネストが浅くなる
  • thenでのやり取りがなくなる

この結果としてコードは読みやすくなり、行数も短く書くことができるようになります。コードを簡潔にわかりやすく書くのは正義です。async/awaitを使える環境にある場合、積極的に使っていきましょう。

参考・関連