web-dev-qa-db-ja.com

Angular 1.6.0:「処理できない可能性がある拒否」エラー

Angular 1.6.0までは、Angularアプリで約束を解決するためのパターンがありました。

    resource.get().$promise
        .then(function (response) {
        // do something with the response
        }, function (error) {
            // pass the error the the error service
            return errorService.handleError(error);
        });

そして、これが私たちがカルマのエラーを引き起こしている方法です:

    resourceMock.get = function () {
        var deferred = $q.defer();
        deferred.reject(error);
        return { $promise: deferred.promise };
    };

現在、1.6.0へのアップデートで、Angularは私たちの単体テストで(Karmaで)拒否された約束に対して "おそらく未処理の拒否"エラーで不平を言っています。しかし、エラーサービスを呼び出す2番目の関数で拒否を処理しています。

Angularは、ここで何を探しているのですか?拒絶反応をどのように「処理」したいのでしょうか。

66
Groucho

このコードをあなたの設定に追加してみてください。私は一度同様の問題を抱えていた、そしてこの回避策はトリックをした。

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

ここに示すコードは、.thenへの呼び出しの前に発生した拒否を処理します。そのような状況では、あなたが.thenに渡す2番目のコールバックが呼び出され、そして拒否が処理されます。

しかし、あなたが.thenを呼び出すという約束が成功すると、それは最初のコールバックを呼び出します。 このコールバックが例外をスローするか、または拒否されたプロミスを返す場合、この結果としての拒否は処理されません。これがまさに Promises/A + 仕様に準拠したpromise実装が機能し、Angular promiseが準拠していることです。

次のコードでこれを説明できます。

function handle(p) {
    p.then(
        () => {
            // This is never caught.
            throw new Error("bar");
        },
        (err) => {
            console.log("rejected with", err);
        });
}

handle(Promise.resolve(1));
// We do catch this rejection.
handle(Promise.reject(new Error("foo")));

もしもあなたがこれをPromises/A +にも準拠しているNodeで実行すれば、

rejected with Error: foo
    at Object.<anonymous> (/tmp/t10/test.js:12:23)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3
(node:17426) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: bar
20
Louis

Angular 1.5.9にロールバックしてテストを再実行することで問題を発見しました。これは単純なインジェクションの問題ですが、Angular 1.6.0は代わりに "Possibly Unhandled Rejection"エラーをスローして実際のエラーを難読化することでこれを置き換えました。

18
Groucho

最初の選択肢は、$ qProvider設定でerrorOnUnhandledRejectionsを推奨されるように設定することでエラーを無効にして隠すことです。Cengkuru Michael

BUTこれはロギングをオフにするだけです。エラー自体は残ります

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

resource.get().$promise
    .then(function (response) {})
    .catch(function (err) {});

リンク:

16

コード内に複数の場所で追加の.catch(function () {})を入力しなくても済むようにするには、decorator$exceptionHandlerに追加します。

これは他のものよりも冗長なオプションですが、1箇所で変更するだけで済みます。

angular
    .module('app')
    .config(configDecorators);

configDecorators.$inject = ["$provide"];
function configDecorators($provide) {

    $provide.decorator("$exceptionHandler", exceptionHandler);

    exceptionHandler.$inject = ['$delegate', '$injector'];
    function exceptionHandler($delegate, $injector) {
        return function (exception, cause) {

            if ((exception.toString().toLowerCase()).includes("Possibly unhandled rejection".toLowerCase())) {
                console.log(exception); /* optional to log the "Possibly unhandled rejection" */
                return;
            }
            $delegate(exception, cause);
        };
    }
};
4
Urielzen

ここで答えを確認してください。

Angular 1.6で処理されていない可能性のある拒否

これは 316f60f で修正されており、修正は v1.6.1リリースに含まれています .

3

ErrorOnUnhandledRejectionをオフにすることで問題を隠すことができますが、エラーには「可能性のある拒否を処理する」必要があることが示されているので、約束にキャッチを追加する必要があります。

resource.get().$promise
    .then(function (response) {
    // do something with the response
    }).catch(function (error)) {
        // pass the error to the error service
        return errorService.handleError(error);
    });

参照: https://github.com/angular-ui/u -router /issues/2889

3
giselleghadyani

テスト実行中も同じ動作を観察しました。本番コードではうまく機能し、テストでのみ失敗するのは不思議です。

あなたのテストを満足させる簡単な解決策はあなたの約束のモックにcatch(angular.noop)を加えることです。上記の例の場合、これは次のようになります。

resourceMock.get = function () {
    var deferred = $q.defer();
    deferred.reject(error);
    return { $promise: deferred.promise.catch(angular.noop) };
};
2

Angular 1.6.7にアップデートした後も同じ問題に直面していましたが、コードを調べたところ、$interval.cancel(interval);にエラーが発生しました。

angular-mocksを最新バージョン(1.7.0)に更新すると、問題は解決しました。

2
Dilip

それはあなたの特定の状況ではないかもしれませんが、私は同様の問題を抱えていました。

私の場合は、angular-i18nを使用し、ロケール辞書を非同期に取得していました。問題は、取得しているjsonファイルが誤ってインデントされていることです(スペースとタブが混在しています)。 GET要求は失敗しませんでした。

インデントを修正すると問題は解決しました。

0
monstercode

私はこれと同じ通知をいくつかの変更を加えた後に表示させました。これは、angularjs $httpサービスを使用して、1つの$qリクエストから複数のリクエストに変更したためです。

私はそれらを配列でラップしていませんでした。例えば.

$q.all(request1, request2).then(...) 

のではなく

$q.all([request1, request2]).then(...)

私はこれが誰かに時間を節約するかもしれないと思います。

0