监视承诺和错误的功能,打破了对承诺

时间:2016-08-17 11:15:44

标签: javascript angularjs promise

找到解决方案

Promises : go to next error function 只需要重新抛出错误。

为什么承诺的参考在侦察时不会执行当时的错误功能?

有两个按钮返回(调用)相同的promise,一个执行ok($ scope.expected() - 按钮呈现红色),其他进入成功函数($ scope.notExpected() - 按钮呈现绿色)并且它是不期望的行为。

当前的解决方案是,包装另一个承诺;



var app = angular.module('thenApp', []);

function ThenCtrl($scope, thenService, $q) {
  $scope.expected = function() {
    return thenService.doIt()
      .then(function() {
        console.log('was a success');
      });
  };

  $scope.notExpected = function() {
    return thenService.doIt()
      .then(function() {
        console.log('was a success');
      }, function() {
        console.log('has failed');
      });
  };

  $scope.solution = function() {
    var deferred = $q.defer();
    thenService.doIt()
      .then(function() {
        deferred.resolve();
        console.log('was a success');
      }, function() {
        deferred.reject();
        console.log('has failed');
      });
    return deferred.promise;
  };
}

app.controller('ThenCtrl', ThenCtrl);

var CLICK_EVENT = 'click';
var TIMEOUT_TO_END_ANIMATION = 1000;
var SUCCESS_CLASS = 'btn-success success';
var FAIL_CLASS = 'btn-error error';
var LOADING_CLASS = 'loading';

/**
 * Inspiration from https://github.com/johannesjo/angular-promise-buttons
 * @param $parse
 * @param $timeout
 * @returns {{scope: {promise: string, stateRedirect: string}, link: link}}
 */
function btnLoader($parse, $timeout) {
  return {
    restrict: 'A',
    require: '?ngClick',
    scope: true,
    link: function(scope, el, attrs) {

      el.addClass('btn-load');

      var promiseWatcher;


      // we need to use evalAsync here, as
      // otherwise the click or submit event
      // won't be ready to be replaced
      scope.$evalAsync(function() {

        var cb = $parse(attrs.ngClick);

        function buttonLoader() {
          // Make sure we run the $digest cycle
          scope.$apply(function() {
            var promise = cb(scope.$parent, {
              $event: CLICK_EVENT
            });

            // only init watcher if not done before
            if (!promiseWatcher) {
              // watch promise to resolve or fail
              promiseWatcher = scope.$watch(function() {
                return promise;
              }, function(nVal) {
                // for regular promises
                if (nVal && nVal.then) {

                  el.unbind(CLICK_EVENT);

                  el.addClass(LOADING_CLASS);
                  el.removeClass(SUCCESS_CLASS);
                  el.removeClass(FAIL_CLASS);

                  nVal.then(function() {
                    // promise was a success
                    el.addClass(SUCCESS_CLASS);

                    if (attrs.alwaysBind) {
                      el.bind(CLICK_EVENT, buttonLoader);
                    }

                  }, function() {
                    // promise was a fail
                    el.addClass(FAIL_CLASS);
                    el.bind(CLICK_EVENT, buttonLoader);
                  }).finally(function() {
                    el.removeClass(LOADING_CLASS);
                    promiseWatcher();
                    promiseWatcher = null;

                    $timeout(function() {
                      el.removeClass(SUCCESS_CLASS);
                      el.removeClass(FAIL_CLASS);
                    }, TIMEOUT_TO_END_ANIMATION);

                  });
                }
              });
            }
          });
        }

        // unbind original click event
        el.unbind(CLICK_EVENT);

        // rebind, but this time watching it's return value
        el.bind(CLICK_EVENT, buttonLoader);

      });
    }
  };
}

app.directive('btnLoader', btnLoader);

function thenService($q, $timeout) {
  thenService.doIt = function() {
    var deferred = $q.defer();
    $timeout(function() {
      deferred.reject(null);
    }, 500);
    return deferred.promise;
  };

  return thenService;
}

app.factory('thenService', thenService);

.loading {
  background: yellow !important;
}
.btn-error {
  background: red !important;
}
.btn-success {
  background: green !important;
}
.btn {
  margin-bottom: 20px;
  border: 1px solid rgba(0, 0, 0, 0.3);
  background: white;
  width: 250px;
  padding: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-transform: uppercase;
}
.btn:hover {
  background: lightgray;
  cursor: pointer;
}

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="thenApp" ng-controller="ThenCtrl">
  <p>
    Button action does not spy on then's error function.
  </p>
  <div class="btn" btn-loader="" always-bind="true" ng-click="expected()">
    As expected
  </div>

  <p>
    Button action spies on then's error function.
  </p>
  <div class="btn" btn-loader="" always-bind="true" ng-click="notExpected()">
    Not expected
  </div>

  <p>
    Solution for spying on then's error function.
  </p>
  <div class="btn" btn-loader="" always-bind="true" ng-click="solution()">
    Solution
  </div>
</div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

需要重新抛出错误。

someService.call().then(function(){
  // success
}, function(e){
  // error
  throw e;
})

Promises : go to next error function