ホームページ  >  に質問  >  本文

Promise のエラーを常に見つけることの重要性

私はプロジェクトで @typescript-eslint/no-floating-promises ルールを使用します。このようなコードを書くと、このルールは文句を言います -

functionReturningPromise()
    .then(retVal => doSomething(retVal));

この Promisecatch ブロックを追加する必要があります。例外処理ブロックにロジックを追加したい場合、これは理にかなっています。しかし、それが必要ない状況もたくさんあります。エラーがスローされたことに満足しています。したがって、このルールによってスローされるエラーを抑制するために、私はこれを行うことになりました -

functionReturningPromise()
    .then((retVal) => doSomething(retVal))
    .catch((エラー) => {
        エラーをスローします。
    });
上記のように catch ブロックを追加しなくても、error は同じようにスローされます (少なくともコンソール出力には表示されます)。したがって、この catch ブロックを明示的に指定する意味がわかりません。私は何か見落としてますか? catch ブロックを追加する場合と追加しない場合で、error がスローされる方法に実際の違いはありますか?

P粉590929392P粉590929392213日前364

全員に返信(1)返信します

  • P粉106711425

    P粉1067114252024-03-20 17:42:08

    コメント投稿者は皆、あなたの質問にうまく答えていますが、これがなぜ重要なのかを例で説明するには、次のコードを想像してください:

    Promise.reject();
    setTimeout(() => console.log('hello'), 1000);

    このコードはかなり無害に見えます。未処理の no-op 約束拒否があり、プログラムは起動後 1 秒後に 'hello' をログに記録します。

    ブラウザでは、まさにこれが起こります。ブラウザは「Uncaught Promise Rejection」エラーをログに記録しますが、それ以外の場合は無視します。

    ただし、NodeJS (Node v15 以降) では、未処理の Promise 拒否は ハード エラーです。 つまり、エラーが検出されるとプロセスが終了します。

    これは、ターミナルでコードを実行することで確認できます (-e は「このコード文字列を評価して実行する」という意味です)

    $ ノード -e "Promise.reject(); setTimeout(() => console.log('hello'), 1000)"
    ノード:内部/プロセス/約束:288
                triggerUncaughtException(err, true /* fromPromise */);
                ^
    
    [UnhandledPromiseRejection: このエラーは、catch ブロックなしで非同期関数内でスローしたか、.catch() で処理されなかった Promise を拒否したことによって発生しました。Promise は、「未定義」という理由で拒否されました。] {
      コード: 'ERR_UNHANDLED_REJECTION'
    }
    
    Node.js v18.12.1

    プロセスが 1 秒前に終了したため、'hello' が出力されないことがわかります。

    期待どおりに動作していることを確認するには、.reject.resolve に変更します。

    $ ノード -e "Promise.resolve(); setTimeout(() => console.log('hello'), 1000)" こんにちは###
    したがって、LTS がサポートされているバージョンを使用して NodeJS アプリケーションを作成している場合は、必ずエラーを処理する必要があります。そうしないと、予期しないクラッシュが発生する危険があります。 

    コードがブラウザ内でのみ実行される場合、障害を処理する必要があるかどうか疑問に思うかもしれません。結局のところ、ユーザーはコンソールを見ないので、何か悪いことが起こったことに気づきません。それで、誰が気にするでしょうか? ? 「コードのみ」の観点から見ると、あなたの考えは正しいですが、ユーザーは何か問題が発生したときにアプリケーションからのフィードバックを求めています。

    次のシナリオを想像してください。Promise は、アプリケーションでユーザーが入力したデータを送信する API 呼び出しの結果を追跡します。何らかの理由で API 呼び出しが失敗した場合、アプリケーションは適切に応答して、何か問題が発生したことをユーザーに伝える必要があります。

    これを処理する別の方法としては、アプリに無限読み込みスピナーが表示されたり、実際にはデータが正常に送信されていないのにユーザーがデータが正常に送信されたと思っていることが考えられます。いずれにしても、それは非常に悪く、壊れたユーザーエクスペリエンスです。

    最後に、実際にはエラーを処理しない

    .catch(e => { throw e })

    のような処理を行います。もちろん、このコードはリンターを沈黙させますが、あなたがやっているのは、新しい拒否された Promise を作成し、それがコンソールに記録されるだけです。代わりに、何らかの方法でエラーをアプリケーションの UI に接続する必要があります。.catch(e => {alert(e); throw e }) のような単純なものの方が良いでしょう。

    返事
    0
  • キャンセル返事