AngularJS: где использовать обещания?



Я видел несколько примеров сервисов входа в Facebook, которые использовали обещания для доступа к FB Graph API.



Пример 1:



this.api = function(item) {
var deferred = $q.defer();
if (item) {
facebook.FB.api('/' + item, function (result) {
$rootScope.$apply(function () {
if (angular.isUndefined(result.error)) {
deferred.resolve(result);
} else {
deferred.reject(result.error);
}
});
});
}
return deferred.promise;
}


и услуги, которые использовали "$scope.$digest() // Manual scope evaluation", когда получил ответ



Пример #2:



angular.module('HomePageModule', []).factory('facebookConnect', function() {
return new function() {
this.askFacebookForAuthentication = function(fail, success) {
FB.login(function(response) {
if (response.authResponse) {
FB.api('/me', success);
} else {
fail('User cancelled login or did not fully authorize.');
}
});
}
}
});

function ConnectCtrl(facebookConnect, $scope, $resource) {

$scope.user = {}
$scope.error = null;

$scope.registerWithFacebook = function() {
facebookConnect.askFacebookForAuthentication(
function(reason) { // fail
$scope.error = reason;
}, function(user) { // success
$scope.user = user
$scope.$digest() // Manual scope evaluation
});
}
}


JSFiddle



вопросы:




  • что такое разница в приведенных выше примерах?

  • что такое причины и делам использовать $q сервис?

  • а как же это работа?

585   4  

4 ответов:

это не будет полный ответ на ваш вопрос, но, надеюсь, это поможет вам и другим, когда вы пытаетесь прочитать документацию на $q сервис. Мне потребовалось некоторое время, чтобы понять это.

давайте отложим AngularJS на мгновение и просто рассмотрим вызовы API Facebook. Оба вызова API используют обратный звонок механизм уведомления абонента, когда ответ от Facebook доступен:

  facebook.FB.api('/' + item, function (result) {
    if (result.error) {
      // handle error
    } else {
      // handle success
    }
  });
  // program continues while request is pending
  ...

это стандартная шаблон для обработки асинхронных операций в JavaScript и других языках.

одна большая проблема с этим шаблоном возникает, когда нужно выполнить последовательность асинхронных операций, где каждая последующая операция зависит от результата предыдущей операции. Вот что делает этот код:

  FB.login(function(response) {
      if (response.authResponse) {
          FB.api('/me', success);
      } else {
          fail('User cancelled login or did not fully authorize.');
      }
  });

сначала он пытается войти в систему, а затем только после проверки того, что вход был успешным, он делает запрос на график ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС.

даже в этом случае, который только связывает вместе две операции, все начинает запутываться. Метод askFacebookForAuthentication принимает обратный вызов для неудачи и успеха, но что происходит, когда FB.login успешно, но FB.api не удается? Этот метод всегда вызывает success обратный вызов независимо от результата FB.api метод.

теперь представьте, что вы пытаетесь закодировать надежную последовательность из трех или более асинхронных операций таким образом, чтобы правильно обрабатывать ошибки на каждом шаге и будут разборчивы для кого-либо еще или даже для вас через несколько недель. Возможно, но это очень легко просто держать вложенность этих обратных вызовов и потерять след ошибок по пути.

теперь давайте отложим API Facebook на мгновение и просто рассмотрим API Angular Promises, реализованный $q сервис. Шаблон, реализованный этой службой, является попыткой превратить асинхронное программирование обратно в нечто, напоминающее линейный ряд простых высказывания, обладающие способностью "выбрасывать" ошибку на любом этапе пути и обрабатывать ее в конце, семантически похожи на знакомые try/catch блок.

рассмотреть этот пример. Скажем, у нас есть две функции, где вторая функция потребляет результат первого:

 var firstFn = function(param) {
    // do something with param
    return 'firstResult';
 };

 var secondFn = function(param) {
    // do something with param
    return 'secondResult';
 };

 secondFn(firstFn()); 

теперь представьте, что firstFn и secondFn оба занимают много времени, поэтому мы хотим обработать эту последовательность асинхронно. Сначала мы создаем новый обработчик вместо очередного успехов обработчик. В большинстве случаев вы можете иметь один обработчик ошибок в конце цепочки, но вы также можете иметь промежуточные обработчики ошибок, которые пытаются восстановить.

чтобы быстро вернуться к вашим примерам (и вашим вопросам), я просто скажу, что они представляют собой два разных способа адаптации API, ориентированного на обратный вызов Facebook, к способу наблюдения за изменениями модели Angular. В первом примере выполняется обертывание вызова API обещание, которое может быть добавлено к области и понимается системой шаблонов Angular. Второй использует более грубый подход, устанавливая результат обратного вызова непосредственно в области, а затем вызывая $scope.$digest() чтобы сделать угловой осведомлены об изменении от внешнего источника.

эти два примера не сопоставимы напрямую, потому что в первом отсутствует шаг входа в систему. Однако, как правило, желательно инкапсулировать взаимодействия с внешними API, как это в отдельном обслуживания, и поставляют результаты к регуляторам как обещания. Таким образом, вы можете держать свои контроллеры отдельно от внешних проблем и тестировать их более легко с помощью mock services.

Я ожидал сложного ответа, который будет охватывать оба: почему они используются в общее и как его использовать в Angular

Это Планк для угловой обещает MVP(минимально жизнеспособный обещание): http://plnkr.co/edit/QBAB0usWXc96TnxqKhuA?p=preview

источник:

(для тех, кому лень кликать на ссылки)

.HTML-код

  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-app="myModule" ng-controller="HelloCtrl">
    <h1>Messages</h1>
    <ul>
      <li ng-repeat="message in messages">{{ message }}</li>
    </ul>
  </body>

</html>

приложение.js

angular.module('myModule', [])

  .factory('HelloWorld', function($q, $timeout) {

    var getMessages = function() {
      var deferred = $q.defer();

      $timeout(function() {
        deferred.resolve(['Hello', 'world']);
      }, 2000);

      return deferred.promise;
    };

    return {
      getMessages: getMessages
    };

  })

  .controller('HelloCtrl', function($scope, HelloWorld) {

    $scope.messages = HelloWorld.getMessages();

  });

(Я знаю, что это не решает ваш конкретный пример Facebook, но я нахожу следующие фрагменты полезными)

через:http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/


обновление 28 февраля 2014:по состоянию на 1.2.0, обещания больше не разрешаются шаблоны. http://www.benlesh.com/2013/02/angularjs-creating-service-with-http.html

(пример plunker использует 1.1.5.)

отложенный представляет собой результат асинхронной операции. Он предоставляет интерфейс, который может использоваться для сигнализации состояния и результата операции, которую он представляет. Он также предоставляет возможность получить соответствующий экземпляр обещание.

Обещание предоставляет интерфейс для взаимодействия с ним, связанный с отсрочкой, и таким образом, позволяет заинтересованным сторонам получить доступ к состоянию и результату отложенной операции.

При создании отложенного, это состояние находится в ожидании и не имеет никакого результата. Когда мы разрешаем() или отклоняем() отложенное, оно изменяет свое состояние на разрешенное или отклоненное. Тем не менее, мы можем получить связанное обещание сразу после создания отложенного и даже назначить взаимодействия с его будущим результатом. Эти взаимодействия будут происходить только после отложенного отклонения или разрешения.

используйте promise в контроллере и убедитесь, что данные доступны или нет

 var app = angular.module("app",[]);
      
      app.controller("test",function($scope,$q){
        var deferred = $q.defer();
        deferred.resolve("Hi");
        deferred.promise.then(function(data){
        console.log(data);    
        })
      });
      angular.bootstrap(document,["app"]);
<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <div ng-controller="test">
    </div>
  </body>

</html>

Comments

    Ничего не найдено.