【问题标题】:Angular 1.6.0: "Possibly unhandled rejection" error [duplicate]Angular 1.6.0:“可能未处理的拒绝”错误[重复]
【发布时间】:2017-04-25 03:22:18
【问题描述】:

在 Angular 1.6.0 之前,我们有一个用于解决 Angular 应用程序中的 Promise 的模式:

    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 到底在寻找什么?它希望我们如何“处理”拒绝?

【问题讨论】:

  • 我在我们的代码库中也注意到了这一点。奇怪的是,使用 chrome 启动器运行该套件可以正常工作。抱怨的是 PhantomJS。
  • 如果你得到这个并且不只是升级,这里是你如何检查你的 Angular 版本:stackoverflow.com/questions/16017699/…
  • 接受的答案建议隐藏错误。重复项建议使用this answer 提供更强大的替代方案。

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


【解决方案1】:

您可以通过关闭 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

【讨论】:

    【解决方案2】:

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

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

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

    而不是

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        为避免在代码中的多个位置输入额外的.catch(function () {}),您可以在$exceptionHandler 中添加decorator

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

        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】:

          请在此处查看答案:

          Possibly unhandled rejection in Angular 1.6

          此问题已通过 316f60f 修复,修复程序包含在 v1.6.1 release 中。

          【讨论】:

          • 在 1.6.2 中仍然得到这个
          • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
          • @MostafaTorbjørnBerg 谢谢。我更新了答案。
          【解决方案6】:

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

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

          纠正缩进解决了问题。

          【讨论】:

            【解决方案7】:

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

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

            【讨论】:

            • 我必须指出,这只是隐藏了错误,根据开发人员的说法,代码中存在一些问题,它只是掩盖了错误。
            • 同意,虽然它可能会回避问题,但根本原因仍然存在,开发人员应该处理错误情况。
            • 具体是什么配置文件?
            【解决方案8】:

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

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

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

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

            链接:

            【讨论】:

              【解决方案9】:

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

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

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

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                • 目前这对我来说是个大问题,因为我正在迁移代码库并替换旧的注入依赖项。您是否找到了一种方法来防止这种混淆并让它抛出真正的错误?
                • 上面的最佳答案将在运行代码中修复它,但如果不回滚到 Angular 1.5.9,我无法让它在 Karma 中抛出错误。
                【解决方案11】:

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

                然而,当您调用.then 的promise 成功时,它会调用第一个回调。 如果此回调抛出异常或返回被拒绝的承诺,则不会处理此导致的拒绝,因为第二个回调不处理第一个导致的拒绝。这就是符合 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
                

                【讨论】:

                • 好点!是的,目的是处理在调用 .then 之前发生的拒绝。触发此拒绝的代码(适用于 Angular 1.5.9)已添加到原始问题中。
                • 如何实际修复询问的模式代码?
                • 好的,修复就像 $promise.then(success).catch(error),catch 会捕获所有错误,更多内容请参见migration的“注意”部分
                • 这真的应该是正确的答案
                • 如果你的函数设计返回一个被拒绝的承诺怎么办?类似于 $http.get() 返回一个承诺的方式,如果请求失败,该承诺会被拒绝。我有返回承诺的函数,在某些情况下它们可以返回 $q.reject(err),似乎 angular 不喜欢这样,除非我破坏警告?
                猜你喜欢
                • 2017-09-21
                • 2017-05-07
                • 1970-01-01
                • 2021-05-26
                • 1970-01-01
                • 1970-01-01
                • 2016-11-10
                • 1970-01-01
                • 2020-04-03
                相关资源
                最近更新 更多