Несъществени Angular обещания

Опитвам се да пренапиша кода за http://m.amsterdamfoodie.nl в по-модерен стил. По принцип приложението Angular на една страница изтегля набор от ресторанти с местоположения и ги поставя на карта. Ако потребителят е района на Амстердам, местоположението на потребителя също се добавя, както и разстоянията до местата.

В момента управлявам асинхронните връщания, използвайки много if (relevant object from other async call exists) then do next step. Бих искал да използвам повече обещания, би било по-добре.

Така че контролът на потока трябва да бъде:

  • Стартирайте изтегляне на данни на ajax и повикване за геолокация
  • ако първо се върне геолокацията, запазете координатите за по-късно
  • once ajax data is downloaded
    • if geolocation available
      • calculate distances to each restaurant, and pass control to rendering code
    • в противен случай незабавно прехвърлете контрола, за да изобразите код
  • ако геолокацията се разреши по-късно, изчислете разстоянията и изобразете отново

Моделите, които намирам в интернет, предполагат, че всички асинхронни повиквания трябва да се върнат успешно, преди да продължат, докато моето повикване за геолокация може да се провали (или да върне местоположение далеч от Амстердам) и това е ОК. Има ли трик, който мога да използвам в този сценарий или условните изрази наистина са правилният начин?


person Simon H    schedule 04.11.2014    source източник
comment
Вашето обещание все още може да resolve успешно, дори ако данните са отрицателни или несъществуващи - третирайте това като успешен резултат. Третирайте reject подобно на catch в try/catch блока и обработвайте фатални изключения.   -  person New Dev    schedule 04.11.2014
comment
Как да проверя дали обещанието за геолокация е разрешено, след като имам данните за ресторанта. Ако не е разрешено, няма да го чакам (тъй като резултатът може да е, че човекът така или иначе не е в Амстердам).   -  person Simon H    schedule 05.11.2014
comment
Може би пропускам нещо, но можете да го разрешите, независимо дали сте получили данните или отрицателния резултат. Това ще бъде приносът към следващата ви стъпка.   -  person New Dev    schedule 05.11.2014
comment
Това, което търсех, беше нещо по-елегантно от трите израза if, сега с удебелен шрифт, които използваха контрола на потока на angular $http и $q. Това може да е пожелателно мислене?   -  person Simon H    schedule 05.11.2014


Отговори (2)


Всеки път, когато използвате .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(...);
}

и след това използвайте $q.all и за двете обещания, което на свой ред създава нов обещание, което се решава веднага след като всички дадени обещания са разрешени.

Забележка: В Q на Крис Ковал, което Услугата $q на Angular се основава на, можете да използвате метода allSettled, който прави почти същото като all, но решава, когато всички обещания са изпълнени (изпълнени или отхвърлени), а не само ако всички обещания са изпълнени. $q на Angular не предоставя този метод, така че можете вместо това да заобиколите това, като изрично накарате неуспешната http заявка да се разреши така или иначе.

Така че тогава можете да направите нещо като:

$q.all([getData(), getGeolocation()])
.then(function(data, geolocation) {
  // `data` is the value that getData() resolved with,
  // `geolocation` is the value that getGeolocation() resolved with.
  // Check the documentation on `$q.all` for this.
  if(geolocation) {
    // Yay, the geolocation data is available and valid, do something
  }

  // Handle the rest of the data
});
person yerforkferchips    schedule 04.11.2014

Може би пропускам нещо... но тъй като нямате зависимости между двете асинхронни извиквания, не виждам защо не можете просто да следвате логиката, която очертахте:

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
  });
person New Dev    schedule 05.11.2014