Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Throwing from $exceptionHandler breaks the digest loop leaving it in a zombie state. #14704

@d-ph

Description

@d-ph

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
When the $exceptionHandler is overridden to throw the thrown exceptions, then the digest loop is sometimes left in a zombie state (i.e. the clearPhase(); is not called).

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).
I tried to create a minimal demo of the bug, but I was unable to reproduce it.

What is the expected behavior?
The digest loop is operational after the exceptions are thrown (i.e. the clearPhase(); is called before leaving the loop).

What is the motivation / use case for changing the behavior?
I'd like the javascript Errors to be thrown instead of being logged to the console. I have a custom error handler set up on the window.onerror event. Errors don't trigger this event, when thrown from angular context (they are logged to the console instead, as per default $exceptionHandler behaviour)

Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
Tested against version: AngularJS v1.5.7-build.4839+sha.a478f69

Other information (e.g. stacktraces, related issues, suggestions how to fix)

// angular.js

      $apply: function(expr) {
        try {
          beginPhase('$apply');
          try {
            // (1)
            return this.$eval(expr);
          } finally {
            clearPhase();
          }
        } catch (e) {
          $exceptionHandler(e);
        } finally {
          try {
            // (2)
            $rootScope.$digest();
          } catch (e) {
            $exceptionHandler(e);
            throw e;
          } finally {
              // (3)
              // clearPhase();
          }
        }
      },

If I add a finally block with a clearPhase(); at position (3), then the digest loop is properly cleaned up in a case of an error being thrown. I tried to create a small demo of this problem, but somehow the demo code throws from the this.$eval(expr)(1), while the code I'm working on is throwing from the $rootScope.$digest()(2). As you can see, when errors are thrown from the (1), then the clearPhase(); is called.

This is probably related with these two PRs:

  1. link
  2. link

The second PR would probably fix the problem, because it adds a giant try..finally block in the .$digest() method. It wasn't merged though.

For now, I'm throwing Errors from my $exceptionHandler using a setTimeout() function, so Angular has an opportunity to get out of the digest loop with a proper clean up.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions