web-dev-qa-db-ja.com

Angular 1.6で未処理の拒否の可能性があります

私はAngularJSでコードを持っています:

service.doSomething()
  .then(function(result) {
      //do something with the result
  });

AngularJS 1.5.9では、次のような.then()セクションにエラーがあります。

service.doSomething()
  .then(function(result) {
      var x = null;
      var y = x.y;
      //do something with the result
  });

明確なエラーメッセージが表示されます。

TypeError:nullのプロパティ 'y'を読み取れません

しかし、同じコードを使用したバージョン1.6では、異なるエラーが発生します。

未処理の拒否の可能性:{} undefined

私はこれが この変更 に関連していることを知っており、単一の解決策は.catch()ブロックを追加することで非常に簡単です:

service.doSomething()
  .then(function(result) {
      var x = null;
      var y = x.y;
      //do something with the result
  })
  .catch(console.error);

今、私は再び私が欲しいものを持っています:

TypeError:nullのプロパティ 'y'を読み取れません

しかし、すべての場所に.catch()ブロックを追加せずに、アプリケーション全体で同じ結果(より詳細なエラー)を取得する方法は?

以下を追加して、これを無効にする提案されたソリューションをテストしました。

$qProvider.errorOnUnhandledRejections(false);

しかし、これにより状況はさらに悪化します-コンソールに何もありません!エラーはどこかに飲み込まれ、まったく記録されません。それがAngularJS 1.6または私の構成に問題があるかどうかはわかりません。

バージョン1.5.9からロギング動作を「復元」する方法はありますか?

編集:

カスタムエラーハンドラーの追加:

.factory('$exceptionHandler', function($log) {
  return function(exception, cause) {
    $log.warn(exception, cause);
  };
})

まったく役に立ちません。エラーハンドラでは、既に「ラップされた」エラーを受け取ります。

29
18
gkalpak

最初のオプションは、推奨されるように$ qProvider構成でerrorOnUnhandledRejectionsを無効にすることでエラーを非表示にすることです Cengkuru Michael

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);

しかしこれはロギングのみをオフにします。エラー自体は残ります

この場合のより良い解決策は次のようになります-.catch()メソッドで拒否を処理する:

service.doSomething()
    .then(function (response) {})
    .catch(function (err) {});

便利なリンク:

15

アンギュラーUIルーターを0.3.2にアップグレードすることにより、バージョン1.6.1で同じ問題を修正しました。

8
Stephen C

この情報は、(私の場合)エラーハンドラーを追加せずにプロミスを作成しているものを追跡するのに役立ちました。問題の議論に埋もれていることがわかりました #2889 "おそらくAngular 1.5.9"による未処理の拒否

Gistは、$qパッチであり、promiseの作成時にスタックトレースをキャッシュし、エラーがトリガーされたときに取得できるようにします。

これを行うには、angularアプリの上部近くのどこかに$qを飾るために次のコードを挿入します。

// Decorate the $q service when app starts
app.decorator('$q', ["$delegate", function($delegate) {
  // Create a new promise object
  var promise = $delegate.when();

  // Access the `Promise` prototype (nonstandard, but works in Chrome)
  var proto = promise.__proto__;

  // Define a setter for `$$state` that creates a stacktrace 
  // (string) and assigns it as a property of the internal `$$state` object.
  Object.defineProperty(proto, '$$state', {
    enumerable: true,
    set: function(val) {
      val.stack = new Error().stack;
      this._$$state = val;
    },
    get: function() {
      return this._$$state;
    }
  });

  return $delegate;
}]);

次に、angularコードで「おそらく未処理の拒否」メッセージを検索し、その行にブレークポイントを設定します。ブレークポイントに到達したら、toCheck.stackの値をコンソールに出力すると、次のように表示されます。

>> toCheck.stack
"set@http://localhost:8000/js/dual-site.js:18:19
Promise@http://localhost:8000/js/angular.js:17008:22
then@http://localhost:8000/js/angular.js:17016:20
catch@http://localhost:8000/js/angular.js:17026:14
SyncStrategy.prototype.send@http://localhost:8000/js/angular-state-machine.js:436:24
StateMachine/this.send@http://localhost:8000/js/angular-state-machine.js:235:16

問題のコードは、Angularのcatch/then関数を呼び出すフレームです。

5
wu-lee

別のケースがあり、finally()ハンドラーをpromiseに追加するとエラーが生成されます。 http://plnkr.co/edit/eT834BkIEooAMvrVcLDe

finally()は新しいプロミスを作成し、そのリゾルバーを呼び出すためです。 (拒否の場合に2番目の拒否)

Plnkrに修正を加えましたが、あまり良く見えません。

4
Rouche

拒否されたプロミスがangular ver1.6.1を使用してangle-ui-router(ui-sref)によって処理されない場合、同じ未処理の拒否エラーが発生しました。この機能はデフォルトで有効になっています。

回避策が必要な場合(推奨されません)、このような未処理のプロミスの拒否をグローバルに黙らせることができます—

app.config(['$qProvider', function ($qProvider) { $qProvider.errorOnUnhandledRejections(false); }]);

3
Yash Vekaria

Catchブロックに次のようなデフォルト値を追加して、このエラーを解決しました。

service.doSomething()
    .then(function(response) {
        var x = null;
        var y = x.y;
    }).catch(function(error) {
        var y = 0;
    });

(私は経験豊富なangular開発者ではないことを考慮してください)

1
onlyjunior

HttpErrorInterceptorのバージョン1.6.1でも問題があります。ある場合、APIが404を返す場合、他のデータで別のリクエストを試行する必要があります。この場合、リクエストとangular未処理の拒否エラーをスローします...

1.5.9をインストールすると、エラーはなくなりました!

0
lolo

errorOnUnhandledRejections(false);私にとって解決策ではありませんでした。

確かに例外ハンドラを定義する必要があります...しかし...タイムアウト関数でラップします:これにより、元の例外/スタックトレースがスローされます。

最初に意図したとおりに、エラーをWebコンソールにエラーとして表示するには:

ng.factory('$exceptionHandler', function($log) {
  return function(exception, cause) {
    // do some some stuff...
    setTimeout(function(){
      // throw the original exception (with correct line #'s etc)
      throw exception;
    })
  };
});

タイムアウトのトリックは次のとおりです。 Promise.catchハンドラー内にスローできないのはなぜですか?

0
nawlbergs