AngularJS链接承诺 - 需要在下一个'然后'之前做好工作

时间:2016-02-25 14:40:03

标签: angularjs angular-promise

我正在开发一个承诺链。第一个调用是$ http调用来检查用户是否存在,如果存在,则会有一堆顺序运行的.then()语句。

我的问题是这个..在第一次调用中,我不想返回$ http请求的承诺,因为如果用户不存在,结果只是一个空数组并且promise会解析,因此触发下一步操作以查找有关用户的信息。我写了以下代码......

(参见评论中关于成为我要问的重要部分的部分)

$scope.checkIfUserExists = function() {
      if (angular.isObject($scope.admin.Inductee.Contactor)) {

        var handleFault = function( fault ) {
          if (typeof(fault) === 'string') {
            switch (fault.toUpperCase()){
              case 'NODATA':
                // Go ahead an save
                $scope.pushInductee();
                break;

              case 'STATUS':
                // just get the 'duplicate records check' sign off of there
                // The save button is disabled by the critical error
                $scope.hideSave = false;
                break;

              case 'ASSIGNED':
                // just get the 'duplicate records check' sign off of there
                // The save button is disabled by the critical error
                $scope.hideSave = true;
                break;

              default:
                $log.error(fault);
                $location.path('/error/default');
            }
          } else {
            $log.error(fault);
            $location.path('/error/default');
          }
        };

        $scope.getMatchingIndData()
          .then($scope.procBusLogic)
          .then($scope.pushInductee) 
          .catch(handleFault);
      } 
    };


////HERE IS THE IMPORTANT PART I AM ASKING ABOUT
    $scope.getMatchingIndData = function() {
      var deferred = $q.defer();
      var locals = {};

  var checkUser = function(dupeJson){
    var checkUserDeferred = $q.defer();

    // abandoned promise replaced with my own
    sttiJoinDataFactory.checkIfUserExistsNurseleader(dupeJson)
      .then(function(results) {
        var data = results.data;
        if (angular.isArray(data) && data.length > 0){
          var highestMatch = data[0];

          for (var i = 0; i < data.length; i++) {
            if (parseInt(data[i].Score) > parseInt(highestMatch.Score)) {
              highestMatch = data[i];
            }
          }

          checkUserDeferred.resolve(highestMatch);

        } else {
          // Reject the 'overall' promise here
          // to effectively break the chain
          return deferred.reject('NODATA');
        }
      })
      .catch(function(fault) {
        // Any other failure should break the chain 
        // of http requests at this point
        return deferred.reject(fault);
      });

      return checkUserDeferred.promise;
    },
    loadindividual = function (highestMatch) {
      return $http stuff about the highestmatch
      // set data in locals
    },
    parallelLoadStatusAndInducteeData = function(individual) {
      return another $http promise based on the last then()
      // set data in locals
    },
    loadCeremonyData = function (inductees){
      return another $http promise based on the last call then()                           // set data in locals
    },
    reportProblems = function( fault ) {
      deferred.reject(fault);
    };

    checkUser($scope.generateDupJson())
    .then(loadindividual, reportProblems) 
    .then(parallelLoadStatusAndInducteeData, reportProblems)
    .then(loadCeremonyData, reportProblems)
    .then(function() { 
      deferred.resolve(locals); 
    })
    .catch( reportProblems );

  return deferred.promise;
};

我必须考虑被放弃的承诺,因为我真的需要承诺在数据回来时解决,如果有NODATA我需要拒绝它。这是在调用函数的链中处理的。

另外,我知道这里的反模式。我正在尽力不嵌套承诺,维护链条,以及处理异常。

1 个答案:

答案 0 :(得分:0)

好的,我有几点意见:

 ...
 // revert if and return immediately
 // to reduce indentation
 if (typeof(fault) !== 'string') {
   $log.error(fault);
   $location.path('/error/default');
   return;
 }
 switch (fault.toUpperCase()) {
 ...

您不需要延迟对象:

var checkUser = function(dupeJson){

  // this is not abandoned because we are returning it
  return sttiJoinDataFactory.checkIfUserExistsNurseleader(dupeJson)
  .then(function(results) {
    var data = results.data;
    if (!angular.isArray(data) || data.length <= 0) {
      return $q.reject('NODATA');
    }

    var highestMatch = data.reduce(function (highest, d) {
      return parseInt(d.Score) > parseInt(highest.Score) ? 
        d : highest;
    }, data[0]);

    return highestMatch;
  }); // you don't need catch here if you're gonna reject it again
}

...

checkUser(...)
  // loadIndividual will be called
  // after everything inside checkUser resolves
  // so you will have your highestMatch
  .then(loadIndividual)
  .then(parallelLoadStatusAndInducteeData)
  .then(loadCeremonyData)
  // you don't need to repeat reportProblems, just catch in the end
  // if anything rejects prior to this point
  // reportProblems will be called
  .catch(reportProblems)
  ...