Javascript 角度1.6.0:“;可能未经处理的拒绝”;错误

Javascript 角度1.6.0:“;可能未经处理的拒绝”;错误,javascript,angularjs,karma-runner,angular-promise,angularjs-1.6,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

在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);
        });
这就是我们如何触发业力错误的原因:

    resourceMock.get = function () {
        var deferred = $q.defer();
        deferred.reject(error);
        return { $promise: deferred.promise };
    };
现在,随着1.6.0的更新,Angular在我们的单元测试中(在Karma中)突然抱怨被拒绝的承诺带有“可能未处理的拒绝”错误。但是我们在调用错误服务的第二个函数中处理拒绝


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

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

但是,当您调用
.then
的承诺成功时,它将调用第一次回调。如果此回调引发异常或返回被拒绝的承诺,则不会处理由此产生的拒绝,因为第二个回调不会处理第一个回调导致的拒绝。这就是符合规范的承诺实现的工作方式,角度承诺也是符合规范的

您可以使用以下代码对此进行说明:

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")));
如果您在节点中运行它,它也符合Promissions/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
被拒绝,错误为:foo
反对。(/tmp/t10/test.js:12:23)
在模块处编译(Module.js:570:32)
在Object.Module.\u extensions..js(Module.js:579:10)
在Module.load(Module.js:487:32)
在tryModuleLoad时(module.js:446:12)
在Function.Module.\u加载(Module.js:438:3)
位于Module.runMain(Module.js:604:10)
运行时(bootstrap_node.js:394:7)
启动时(bootstrap_node.js:149:9)
在bootstrap_node.js:509:3
(节点:17426)未处理的PromisejectionWarning:未处理的承诺拒绝(拒绝id:2):错误:bar

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

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

让您的测试满意的简单解决方案是在promise mock中添加
catch(angular.noop)
。在上述示例中,应如下所示:

resourceMock.get=函数(){
var deferred=$q.deferred();
延迟。拒绝(错误);
返回{$promise:deferred.promise.catch(angular.noop)};

};请在此处检查答案:

此问题已通过修复,修复包含在中


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

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

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

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

参考资料:

第一个选项是按照建议在$qProvider配置中配置
ErrorOnUnhandRejections
以禁用错误来隐藏错误

但是这只会关闭日志记录。错误本身将继续存在

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

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

  • 角度:

    • 这可能不是你的特殊情况,但我也有类似的问题

      在我的例子中,我使用angular-i18n,并异步获取区域设置词典。问题是它得到的json文件缩进不正确(混合空格和制表符)。获取请求没有失败


      更正缩进解决了问题。

      为了避免在代码中的多个位置键入额外的
      .catch(function(){})
      ,您可以在
      $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);
              };
          }
      };
      

      在升级到Angular 1.6.7之后,我也面临着同样的问题,但是当我查看代码时,
      $interval.cancel(interval)抛出了错误用于我的案例


      当我将
      angular Mock
      更新到最新版本(1.7.0)时,我的问题得到了解决。

      在做了一些更改后,我看到了同样的通知。原来是因为我使用angularjs
      $q
      服务将一个
      $http
      请求更改为多个请求

      我没有把它们包装成一个阵列。e、 g

      $q.all(request1, request2).then(...) 
      
      而不是

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

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

      很好!是的,目的是处理调用之前发生的拒绝。然后。触发此拒绝的代码(适用于Angular 1.5.9)已添加到原始问题中。如何实际修复询问的模式代码?好的,修复类似于$promise.then(success)。catch(error),其中catch捕获所有错误,更多信息请参见“备注”这一节应该是正确的答案如果你的函数返回一个被拒绝的设计承诺呢?与$http.get()返回承诺的方式类似,根据设计,如果请求失败,将拒绝该承诺。我有返回承诺的函数,在某些情况下,它们可以返回$q.reject(err),似乎angular不喜欢这样,除非我破坏了警告?我在我们的代码库中也注意到了这一点。奇怪的是,使用chrome launcher运行套件效果很好。PhantomJS是一个抱怨的人。如果你得到了这一点,而不是仅仅升级,下面是你如何检查你的角度版本:公认的答案建议隐藏错误。副本建议使用更健壮的替代方法。这对我来说是一个大问题,因为我正在迁移代码库并替换旧的注入依赖项。你有没有找到一种方法来防止这种情况