Angular 1.6.0:"可能未处理的拒绝"错误

时间:2016-12-09 15:38:55

标签: javascript angularjs karma-runner angular-promise angularjs-1.6

我们在Angular应用程序中有一个解决承诺的模式,直到Angular 1.6.0为止我们一直很好:

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

以下是我们如何在Karma中触发错误:

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

现在,随着1.6.0的更新,Angular突然在我们的单元测试中(在Karma中)抱怨被拒绝的承诺,其中包括"可能未处理的拒绝"错误。但我们正在处理调用错误服务的第二个函数中的拒绝。

Angular究竟在寻找什么?它是如何让我们处理"拒绝?

11 个答案:

答案 0 :(得分:66)

尝试将此代码添加到您的配置中。我曾经遇到过类似的问题,而且这种解决方法可以解决问题。

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

答案 1 :(得分:20)

您展示的代码将处理在调用.then之前发生的拒绝。在这种情况下,您将调用传递给.then的第二个回调,并将处理拒绝。

然而,当您致电.then的承诺成功时,它会调用第一个回调。 如果此回调引发异常或返回被拒绝的承诺,则不会处理此结果拒绝,因为第二个回调不会处理第一个引起的拒绝。这就是承诺实现符合Promises/A+规范的工作方式,以及Angular承诺是否合规。

您可以使用以下代码说明这一点:

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")));

如果你在Node中运行它,它也符合Promises / A +,你得到:

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

答案 2 :(得分:18)

通过回滚到Angular 1.5.9并重新运行测试找到问题。这是一个简单的注入问题,但Angular 1.6.0通过抛出“可能未处理的拒绝”错误取代了这一点,混淆了实际的错误。

答案 3 :(得分:16)

第一个选项只是隐藏错误并通过在$ qProvider配置中配置errorOnUnhandledRejections建议Cengkuru Michael

来隐藏错误

但是这只会关闭日志记录。错误本身将保持

在这种情况下,

更好的解决方案 - 使用.catch(fn)方法处理拒绝:

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

LINKS:

答案 4 :(得分:4)

为避免在多个地方的代码中输入其他.catch(function () {}),您可以向decorator添加$exceptionHandler

这是一个比其他选项更冗长的选项,但您只需在一个地方进行更改。

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);
        };
    }
};

答案 5 :(得分:3)

请在这里查看答案:

Possibly unhandled rejection in Angular 1.6

  

此问题已修复为316f60f,修正案已包含在v1.6.1 release中。

答案 6 :(得分:3)

您可以通过关闭errorOnUnhandledRejections来掩盖问题,但错误表明您需要处理可能的拒绝问题&#34;所以你只需要为你的承诺添加一个捕获。

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/ui-router/issues/2889

答案 7 :(得分:2)

我在测试执行期间观察到了相同的行为。奇怪的是,生产代码工作正常并且仅在测试时失败。

让您的测试满意的简单解决方案是将catch(angular.noop)添加到您的promise模拟中。如果是上面的例子,它应该是这样的:

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

答案 8 :(得分:2)

在更新到Angular 1.6.7后我也遇到了同样的问题但是当我查看代码时,typeof(MyList<>).GetMethod("Add").DeclaringType.GetGenericTypeDefinition() 为我的案例引发了错误

我将var instantiationListArgs = typeof(MyList<>).GetMethod("Add").DeclaringType.GetGenericArguments(); var myListArg = typeof(MyList<>).GetGenericArguments(); var listArgs = typeof(List<>).GetGenericArguments(); Console.WriteLine(myListArg[0] == instantiationListArgs[0]); // Will output true, List was instantiated for the T in MyList Console.WriteLine(listArgs[0] == instantiationListArgs[0]); // Will be false. The generic argument is different then the T in the free List<> 更新为最新版本(1.7.0)后,我的问题得到了解决。

答案 9 :(得分:0)

这可能不是你的特殊情况,但我遇到了类似的问题。

在我的情况下,我使用angular-i18n,并异步获取语言环境字典。问题是它获得的json文件被错误缩进(混合空格和制表符)。 GET请求没有失败。

纠正缩进解决了问题。

答案 10 :(得分:0)

进行一些更改后,我也出现了同样的提示。原来是因为我已使用angularjs $http服务将单个$q请求更改为多个请求。

我没有将它们包装成阵列。例如

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

而不是

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

我希望这可以节省一些时间。