如何在两个连续的角度服务呼叫期间中止/取消第一个呼叫的承诺

How to abort/cancel promise for first call during 2 consecutive angular service calls?

本文关键字:呼叫 承诺 第一个 取消 服务 连续 两个      更新时间:2023-09-26

当在下拉项选择上通过$http angular service进行两次连续的服务调用时,假设第一次调用需要时间才能返回,第二次调用在第一次调用解析之前返回,则它会显示第二项选择的第一次调用的数据。

所以,如果在第一次调用解析之前再次进行服务调用,是否有任何方法可以中止第一次承诺。

为了演示的目的,我创建了一个示例plunkar,它有几个项目的下拉列表,我添加了明确的条件,在选择第一个项目时,它比其他项目花费的时间要长一些。所以选择第一个项目并立即选择第二个项目来再现场景,检查屏幕上显示的最喜欢的书。

感谢您的帮助!

服务代码:

app.factory('bookService', function($http, $q, $timeout) {
  return {
    getBook: function(id) {
      var promise = $q.defer();
      var timeoutSpan = id == 1 ? 3000 : 500;
      $http.get("favouriteBooks.json").success(function(data) {
        $timeout(function() {
          promise.resolve(data.filter(function(obj) {
            return obj.id == id
          }));
        }, timeoutSpan);
      }).error(function(msg) {
        promise.reject(msg);
      })
      return promise.promise;
    }
  }
});

我找到了两种方法来处理这种情况-

案例1:在服务级别创建全局$q deffer对象,并在调用$http请求之前检查该对象是否有值。如果这个deffer对象有值,那么显式解析它。Plunkar代码-代码片段

服务代码:

app.factory('bookService', function($http, $q, $timeout, bookConstants) {
  var service = {};
  service.mypromise = null;
  service.getBook = function(id) {
    if (service.mypromise) {
      service.mypromise.resolve(bookConstants.EXPLICIT_CANCEL);
      service.mypromise = null;
    }
    service.mypromise = $q.defer();
    var timeoutSpan = id == 1 ? 3000 : 500;
    $http.get("favouriteBooks.json").success(function(data) {
      $timeout(function() {
        if (service.mypromise) {
          service.mypromise.resolve(data.filter(function(obj) {
            service.mypromise = null;
            return obj.id == id
          }))
        }
      }, timeoutSpan);
    }).error(function(msg) {
      service.mypromise.reject(msg);
    })
    return service.mypromise.promise;
  }
  return service;
});

情况2:返回$q deffer对象作为服务响应,并将其维护在控制器级别。在连续服务调用的情况下,首先检查并明确解决第一个服务调用,然后继续其他服务调用。Plunkar代码-代码片段

示例代码:

$scope.getSelectedValue = function() {
    var id = $scope.selitem.id
    $scope.cancel();
    var bookPromise = bookService.getBook(id);
    $scope.requests.push(bookPromise);
    bookPromise.promise.then(getBookSuccess)
      .catch(errorCallback)
      .finally(getBookComplete);
  }
  function getBookSuccess(favouriteBooks) {
    if (favouriteBooks == 'User Cancelled') {
      return;
    }
    var books = '';
    angular.forEach(favouriteBooks, function(book) {
      books += book.bookName + ' '
    });
    $scope.selectedvalues = 'Name: ' + $scope.selitem.name +
      ' Id: ' + $scope.selitem.id + ' Favourite Book(s): ' + books;
  }
  function errorCallback(errorMsg) {
    console.log('Error Message: ' + errorMsg);
  }
  function getBookComplete() {
    console.log('getBook Has Completed!');
  }
  $scope.cancel = function() {
    if ($scope.requests) {
      angular.forEach($scope.requests, function(request) {
        request.resolve('User Cancelled');
        clearRequest(request);
      })
    }
  };
  var clearRequest = function(request) {
    $scope.requests.splice($scope.requests.indexOf(request), 1);
  };
}]);
app.factory('bookService', function($http, $q, $timeout) {
  var service = {};
  service.getBook = function(id) {
    var promise = $q.defer();
    var timeoutSpan = id == 1 ? 3000 : 500;
    $http.get("favouriteBooks.json").success(function(data) {
      $timeout(function() {
        promise.resolve(data.filter(function(obj) {
          return obj.id == id
        }))
      }, timeoutSpan);
    }).error(function(msg) {
      promise.reject(msg);
    })
    return promise;
  }
  return service;
});

您可以使用以下命令等待两个或多个承诺$q.all([promise1,promise2]).then(function(data){....});

要访问第一个promise的数据,只需使用data[0],第二个promise返回值保存在data[1]中,依此类推…