73

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

以下是我们在 Karma 中触发错误的方式:

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

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

Angular 到底在这里寻找什么?它希望我们如何“处理”拒绝?

4

11 回答 11

65

尝试将此代码添加到您的配置中。我曾经遇到过类似的问题,这个解决方法起到了作用。

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);
于 2017-02-02T02:15:07.927 回答
25

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

但是,当您调用的承诺.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
于 2016-12-09T16:31:21.617 回答
22

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

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

在这种情况下,更好的解决方案是 - 使用以下方法处理拒绝.catch(fn)

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

链接:

于 2017-07-28T08:12:20.093 回答
19

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

于 2016-12-12T16:08:12.887 回答
7

为避免.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);
        };
    }
};
于 2018-05-27T19:10:35.227 回答
5

您可以通过关闭 errorOnUnhandledRejections 来掩盖问题,但错误表明您需要“处理可能的拒绝”,因此您只需在您的承诺中添加一个 catch。

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

于 2017-05-16T18:32:21.137 回答
3

请在此处查看答案:

Angular 1.6 中可能未处理的拒绝

这已通过316f60f修复,该修复包含在v1.6.1 版本中。

于 2016-12-23T04:20:18.443 回答
2

我在测试执行期间观察到了相同的行为。奇怪的是,在生产代码上运行良好并且只在测试中失败。

使您的测试满意的简单解决方案是添加catch(angular.noop)到您的 Promise 模拟中。在上面的示例中,它应该如下所示:

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

于 2016-12-15T10:06:48.210 回答
2

更新到 Angular 1.6.7 后我也遇到了同样的问题,但是当我查看代码时,$interval.cancel(interval);我的情况出现了错误

一旦我更新angular-mocks到最新版本(1.7.0),我的问题就得到了解决。

于 2018-06-04T16:21:52.557 回答
1

在进行一些更改后,我也出现了同样的通知。原来是因为我使用 angularjs服务在单个$http请求到多个请求之间进行了更改。$q

我没有将它们包装在一个数组中。例如

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

而不是

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

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

于 2018-06-26T14:16:44.177 回答
0

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

就我而言,我使用的是 angular-i18n,并异步获取语言环境字典。问题是它获得的 json 文件缩进不正确(混合空格和制表符)。GET 请求没有失败。

纠正缩进解决了这个问题。

于 2018-01-29T13:45:41.620 回答