Javascriptで非同期処理を同期処理にする方法

最近、firebase-idtoken-getterというライブラリを公開したのですが、Firebase SDKおよびFirebase Admin SDKの関数を利用する必要がありました。

Firebase SDK、Firebase Admin SDKから提供されるインターフェースは非同期の関数ですが、コールバック地獄を避けるためSDKから提供される関数を同期的に扱いたいというシーンです。

Javascriptを使う上で(個人的には)非常に分かりにくいと感じる同期処理について、自分の書き方を紹介します。

async/await、そして、Promiseを利用して非同期処理を同期処理に変換する

async/awaitは呼ぶ側、Promiseは呼ばれる側

下記のように呼びたい形、呼ばれる関数があったとします。

Javascriptで同期的に処理を行う場合はasync/await、Primiseを利用する必要あります。
async/awaitは呼ぶ側で利用し、Promiseは呼ばれる側で利用します。

Step.1 呼ばれる側をPromise化

まず呼ばれる側のPromiseですが、Promise内の関数でresolve()、および、reject()が実行されるまで関数がリターンされることを待ってくれます。
func_Aとfunc_Bの呼ばれる側を書き換えると下記のような感じになります。

・呼ばれる側
// 大きく関数でラップする
funcAWrapper()
    // Promiseで包む
    return new Promise((resolve, reject) =>
        funcA().then((result) => {
             // resolveまたはrejectを実行するまで関数の終了が待たれる
             resolve(result)
        }).catch((error) => {
             // resolveまたはrejectを実行するまで関数の終了が待たれる
             reject(error)
        })
    );
}


// 大きく関数でラップする
funcBWrapper(arg)
    // Promiseで包む
    return new Promise((resolve, reject) =>
        funcB(arg).then((result) => {
             // resolveまたはrejectを実行するまで関数の終了が待たれる
             resolve(result)
        }).catch((error) => {
             // resolveまたはrejectを実行するまで関数の終了が待たれる
             reject(error)
        })
    );
}

Step.2 呼ぶ側にawaitを付与

そんなPromiseを使った関数をresolve、rejectが呼ばれるまで待つための命令がawaitで、Promiseが含まれている関数を呼び出すところに設定します。

・呼ぶ側
funcTestProcess = () => {

    // 呼び出すところにawaitを付与する
    let result_1 = await funcAWrapper();

    // 呼び出すところにawaitを付与する
    let result_2 = await funcAWrapper(result_1);

}

Step.3 呼び出す側の全体にasyncを付与

最後に呼び出す側の全体にasyncを付与します。

・呼ぶ側
// asyncを付与する
async funcTestProcess = () => {

    // 呼び出すところにawaitを付与する
    let result_1 = await funcAWrapper();

    // 呼び出すところにawaitを付与する
    let result_2 = await funcAWrapper(result_1);

}

こんな感じで非同期だった処理を同期的に実行することができました。
Javascript歴がそんなに長くないため、なぜ多くのJavascriptの処理に非同期が使われるのか、歴史的背景がよくわかっていないのですが、参考になれば幸いです。