Skip to content

Files

Latest commit

f85ea1a · Dec 20, 2021

History

History
117 lines (99 loc) · 5.67 KB

async-function-await.adoc

File metadata and controls

117 lines (99 loc) · 5.67 KB

await

Async Functionはasync/awaitとも呼ばれることがあります。 この呼ばれ方からも分かるように、Async Functionとawait式は共に利用します。

await式はAsync Function内でのみ利用できます。 await式は右辺のPromiseインスタンスがFulfilledまたはRejectedになるまで、その行(文)で非同期処理の完了を待ちます。 そしてPromiseインスタンスの状態が変わると、次の行(文)から処理を再開します。

async function asyncMain() {
    // PromiseがFulfilledまたはRejectedとなるまで待つ
    await Promiseインスタンス;
    // Promiseインスタンスの状態が変わったら処理を再開する
}

通常の処理の流れでは、非同期処理を実行した場合にその非同期処理の完了を待つことなく、次の行(次の文)を実行します。 しかしawait式では非同期処理を実行し完了するまで、次の行(次の文)を実行しません。 そのためawait式を使うことで非同期処理が同期処理のように上から下へと順番に実行するような流れで書けます。

// async functionは必ずPromiseを返す
async function doAsync() {
    // 非同期処理
}
async function asyncMain() {
    // doAsyncの非同期処理が完了するまでまつ
    await doAsync();
    // 次の行はdoAsyncの非同期処理が完了されるまで実行されない
    console.log("この行は非同期処理が完了後に実行される");
}

await式はであるため右辺(Promiseインスタンス)の評価結果を値として返します。 このawait式の評価方法は評価するPromiseの状態(FulfilledまたはRejected)によって異なります。

await式の右辺のPromiseがFulfilledとなった場合は、resolveされた値がawait式の返り値となります。

次のコードでは、await式の右辺にあるPromiseインスタンスは42という値でresolveされています。 そのためawait式の返り値は42となり、value変数にもその値が入ります。

async function asyncMain() {
    const value = await Promise.resolve(42);
    console.log(value); // => 42
}
asyncMain(); // Promiseインスタンスを返す

これはPromiseを使って書くと次のコードと同様の意味となります。 await式を使うことでコールバック関数を使わずに非同期処理の流れを表現できていることがわかります。

function asyncMain() {
    return Promise.resolve(42).then((value) => {
        console.log(value); // => 42
    });
}
asyncMain(); // Promiseインスタンスを返す

await式の右辺のPromiseがRejectedとなった場合は、その場でエラーをthrowします。 また「async-function-syntax」で紹介したように、Async Function内で発生した例外は自動的にキャッチされます。 そのためawait式でPromiseがRejectedとなった場合は、そのAsync FunctionがRejectedなPromiseを返すことになります。

次のコードでは、await式の右辺にあるPromiseインスタンスがRejectedの状態になっています。 そのためawait式はエラーthrowします。そのエラーを自動的にキャッチするため、asyncMain関数はRejectedなPromiseを返します。

async function asyncMain() {
    const value = await Promise.reject(new Error("エラーメッセージ"));
    // await式で例外が発生したため、この行は実行されません
}
// Async Functionは自動的に例外をキャッチできる
asyncMain().catch((error) => {
    console.log(error.message); // => "エラーメッセージ"
});

await式がエラーをthrowするということは、そのエラーはtry…​catch構文でキャッチできます。 通常の非同期処理では完了する前に次の行が実行されてしまうためtry…​catch構文ではエラーをキャッチできませんでした。 そのためPromiseではcatchメソッドを使いPromise内で発生したエラーをキャッチしていました。(Promise.prototype.done とは何か?を参照)

次のコードでは、await式で発生した例外をtry…​catch構文でキャッチしています。

async function asyncMain() {
    // await式のエラーはtry...catchできる
    try {
        // `await`式で評価した右辺のPromiseがRejectedとなったため、例外がthrowされる
        const value = await Promise.reject(new Error("エラーメッセージ"));
        // await式で例外が発生したため、この行は実行されません
    } catch (error) {
        console.log(error.message); // => "エラーメッセージ"
    }
}
asyncMain().then(() => {
    console.log("この行は実行されます");
}, (error) => {
    // すでにtry...catchされているため、この行は実行されません
});

このようにawait式を使うことで、try…​catch構文のように非同期処理を同期処理と同じ構文を使って扱えます。 またコードの見た目も同期処理と同じように、その行(その文)の処理が完了するまで次の行を評価しないという分かりやすい形になるのは大きな利点です。