web-dev-qa-db-ja.com

Async / Awaitを使用したTry ... Catch構文の修正

TypeScriptなどで利用可能な新しいAsync/Await機能の平坦性が好きです。しかし、後で使用するためにtry...catchブロックの外側でawaitingである変数を宣言しなければならないという事実が好きではありません。そのようです:

let createdUser
try {
    createdUser = await this.User.create(userInfo)
} catch (error) {
    console.error(error)
}

console.log(createdUser)
// business
// logic
// goes
// here

間違っている場合は修正してください。ただし、try本体に複数行のビジネスロジックを配置するのがベストプラクティスのようですnotので、createdUserを宣言する代わりにブロック、ブロック内での割り当て、およびその後の使用。

この場合のベストプラクティスは何ですか?

47
freedomflyer

Tryボディに複数行のビジネスロジックを配置しないことがベストプラクティスのようです

実際にそうだと思います。通常、値の操作からの例外をcatchallしたい場合:

try {
    const createdUser = await this.User.create(userInfo);

    console.log(createdUser)
    // business logic goes here
} catch (error) {
    console.error(error) // from creation or business logic
}

Promiseからのエラーのみをキャッチして処理する場合、3つの選択肢があります。

  • 変数を外部で宣言し、例外があったかどうかに応じて分岐します。それは次のようなさまざまな形をとることができます

    • catchブロック内の変数にデフォルト値を割り当てます
    • return Earlyまたはre _throwcatchブロックからの例外
    • catchブロックが例外をキャッチしたかどうかにフラグを設定し、if状態でテストします
    • 割り当てられた変数の値をテストします
    let createdUser; // or use `var` inside the block
    try {
        createdUser = await this.User.create(userInfo);
    } catch (error) {
        console.error(error) // from creation
    }
    if (createdUser) { // user was successfully created
        console.log(createdUser)
        // business logic goes here
    }
    
  • キャッチした例外のタイプをテストし、それに基づいて処理または再スローします。

    try {
        const createdUser = await this.User.create(userInfo);
        // user was successfully created
        console.log(createdUser)
        // business logic goes here
    } catch (error) {
        if (error instanceof CreationError) {
            console.error(error) // from creation
        } else {
            throw error;
        }
    }
    

    残念ながら、標準のJavaScript(まだ)では 条件付き例外 の構文サポートはありません。

  • then/tryの代わりに catch 2つのコールバックを使用 を使用します。これは最もleastい方法であり、その単純さと正確さについても私の個人的な推奨事項です。タグ付きエラーや結果値の外観に依存せず、約束の履行と拒否を区別します。

    await this.User.create(userInfo).then(createdUser => {
        // user was successfully created
        console.log(createdUser)
        // business logic goes here
    }, error => {
        console.error(error) // from creation
    });
    

    もちろん、コールバック関数を導入するという欠点があります。つまり、break/continueループを簡単に実行したり、外部関数から早期にreturnsを実行したりすることはできません。

38
Bergi

もう1つの簡単な方法は、promise関数に.catchを追加することです。例:

const createdUser = await this.User.create(userInfo).catch( error => {
// handle error
})
7
nevf

@Bergi Answerは良いですが、古いthen()メソッドに戻る必要があるため、最善の方法ではないと思うので、非同期関数でエラーをキャッチする方が良いと思います

async function someAsyncFunction(){
    const createdUser = await this.User.create(userInfo);

    console.log(createdUser)
}

someAsyncFunction().catch(console.log);
  • しかし、同じ関数に多くのawaitがあり、すべてのエラーをキャッチする必要がある場合はどうでしょうか。

to()関数を宣言できます

function to(promise) {
    return promise.then(data => {
        return [null, data];
    })
    .catch(err => [err]);
}

その後

async function someAsyncFunction(){
    let err, createdUser, anotherUser;

    [err, createdUser] = await to(this.User.create(userInfo));

    if (err) console.log(`Error is ${err}`);
    else console.log(`createdUser is ${createdUser}`);


    [err, anotherUser] = await to(this.User.create(anotherUserInfo));

    if (err) console.log(`Error is ${err}`);
    else console.log(`anotherUser is ${anotherUser}`);
}

someAsyncFunction();

これを読むときは、「this.User.createを待ちます」。

最後に、モジュール「to.js」を作成するか、単に await-to-js モジュールを使用できます。

to関数の詳細については、 この投稿 で入手できます

0
Ivan