非必要的角度承诺

时间:2014-11-04 07:50:04

标签: angularjs asynchronous angular-promise

我试图以更现代的方式重写http://m.amsterdamfoodie.nl的代码。基本上单页Angular app下载一组带有位置的餐馆并将它们放在地图上。如果用户是阿姆斯特丹地区,那么也会添加用户的位置,以及到地方的距离。

目前,我使用大量if (relevant object from other async call exists) then do next step来管理异步返回。我想更多地使用承诺会更好。

因此,流量控制应该是:

  • 启动ajax数据下载和地理位置调用
  • 如果地理位置首先返回,则存储coords以供日后使用
  • 下载ajax数据
    • 如果地理位置可用
      • 计算到每家餐馆的距离,并将控制传递给呈现代码
    • else立即传递控制以呈现代码
  • 如果地理位置稍后解决,则计算距离并重新渲染

我在互联网上找到的模式假设所有异步调用必须在继续之前成功返回,而我的地理位置调用可能会失败(或返回远离阿姆斯特丹的位置)并且没有问题。有没有我可以在这种情况下使用的技巧或条件语句真的要走了吗?

2 个答案:

答案 0 :(得分:0)

每次使用.then时,您基本上都会根据之前的承诺及其状态创建新承诺。你可以利用它(你应该)。

您可以采取以下措施:

function getGeolocation() {
  return $http.get('/someurl').then(
    function resolveHandler(response) {
      // $http.X resolves with a HTTP response object.
      // The JSON data is on its `data` attribute
      var data = response.data;

      // Check if the data is valid (with some other function).
      // By this, I mean e.g. checking if it is "far from amsterdam",
      // as you have described that as a possible error case
      if(isValid(data)) {
        return data;
      }
      else {
        return null;
      }
    },
    function rejectHandler() {
      // Handle the retrieval failure by explicitly returning a value
      // from the rejection handler. Null is arbitrarily chosen here because it
      // is a falsy value. See the last code snippet for the use of this
      return null;
    }
  );
}

function getData() {
  return $http.get('/dataurl').then(...);
}

然后在两个promises上使用$q.all,这反过来会创建一个新的承诺,一旦所有给定的承诺得到解决就会立即解决。

注意:在Kris Kowal's Q所基于的Angular's $q service中,您可以使用allSettled方法,该方法与{{1}几乎相同},但当所有承诺已结算(已履行或已拒绝),并且不仅所有承诺都已履行时结算。 Angular的$ q不提供此方法,因此您可以通过明确地使失败的http请求解决来解决此问题。

那么,你可以这样做:

all

答案 1 :(得分:0)

也许我错过了一些东西......但由于两个异步调用之间没有依赖关系,我不明白为什么你不能遵循你概述的逻辑:

var geoCoordinates = null;
var restaurants = null;
var distances = null;

getRestaurantData()
  .then(function(data){
     restaurants = data;
     if (geoCoordinates) {
        distances = calculate(restaurants, geoCoordinates);
     }
     // set $scope variables as needed
});

getGeoLocation()
  .then(function(data){
     geoCoordinates = data;
     if (restaurants){
        distances = calculate(restaurants, geoCoordinates)
     }
     // set $scope variables as needed
  });