function completeTask(fn, taskType) {
    taskType = taskType || DEFAULT_TASK_TYPE;

    try {
      fn();
    } finally {
      decTaskCount(taskType);

      var countForType = taskCounts[taskType];
      var countForAll = taskCounts[ALL_TASKS_TYPE];

      // If at least one of the queues (`ALL_TASKS_TYPE` or `taskType`) is empty, run callbacks.
      if (!countForAll || !countForType) {
        var getNextCallback = !countForAll ? getLastCallback : getLastCallbackForType;
        var nextCb;

        while ((nextCb = getNextCallback(taskType))) {
          try {
            nextCb();
          } catch (e) {
            log.error(e);
          }
        }
      }
    }
  }
@ngdoc input
@name input[email]

@description
Text input with email validation. Sets the `email` validation error key if not a valid email
address.

<div class="alert alert-warning">
**Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
</div>

@param {string} ngModel Assignable AngularJS expression to data-bind to.
@param {string=} name Property name of the form under which the control is published.
@param {string=} required Sets `required` validation error key if the value is not entered.
@param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
   the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
   `required` when you want to data-bind to the `required` attribute.
@param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
   minlength.
@param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
   maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
   any length.
@param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
   that contains the regular expression body that will be converted to a regular expression
   as in the ngPattern directive.
@param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
   does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
   If the expression evaluates to a RegExp object, then this is used directly.
   If the expression evaluates to a string, then it will be converted to a RegExp
   after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
   `new RegExp('^abc$')`.<br />
   **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
   start at the index of the last search's match, thus not taking the whole input value into
   account.
@param {string=} ngChange AngularJS expression to be executed when input changes due to user
   interaction with the input element.

@example
      <example name="email-input-directive" module="emailExample">
        <file name="index.html">
         <script>
           angular.module('emailExample', [])
             .controller('ExampleController', ['$scope', function($scope) {
               $scope.email = {
                 text: 'me@example.com'
               };
             }]);
         </script>
           <form name="myForm" ng-controller="ExampleController">
             <label>Email:
               <input type="email" name="input" ng-model="email.text" required>
             </label>
             <div role="alert">
               <span class="error" ng-show="myForm.input.$error.required">
                 Required!</span>
               <span class="error" ng-show="myForm.input.$error.email">
                 Not valid email!</span>
             </div>
             <tt>text = {{email.text}}</tt><br/>
             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
           </form>
         </file>
        <file name="protractor.js" type="protractor">
          var text = element(by.binding('email.text'));
          var valid = element(by.binding('myForm.input.$valid'));
          var input = element(by.model('email.text'));

          it('should initialize to model', function() {
            expect(text.getText()).toContain('me@example.com');
            expect(valid.getText()).toContain('true');
          });

          it('should be invalid if empty', function() {
            input.clear();
            input.sendKeys('');
            expect(text.getText()).toEqual('text =');
            expect(valid.getText()).toContain('false');
          });

          it('should be invalid if not email', function() {
            input.clear();
            input.sendKeys('xxx');

            expect(valid.getText()).toContain('false');
          });
        </file>
      </example>