Promise представляет результат выполения асинхронной операции. Promise-объект определяет методы, которые регистрируют функцию, вызываемую при завершении асинхронной операции. Переделаем предыдущий пример так, чтобы он использовал promise-объект и сервис $q. Файл с данными в формате json остается тем же самым. Вынесем все действия по загрузке данных в отдельный сервис. Пусть это будет файл dataService.js со следующим содержимым:
questApp.factory('dataService', function($http, $q){ return{ getData: function(){ var deferred = $q.defer(); $http({method: 'GET', url: 'question.json'}). then (function success(response) { deferred.resolve(response.data.question); },function error(response) { deferred.reject(response.status); } ); return deferred.promise; } } })
По сути этот сервис напоминает тот же, что делался в первой теме данной главы. В метод
questApp.factory
передаем название сервиса и функцию, принимающую два параметра - $http и $q. Далее в функции getData
мы создаем deferred-объект: var deferred = $q.defer();
Суть создания deferred-объекта заключается в том, что он раскрывает, во-первых, api по выполнению операций. А во-вторых, он содержит ассоциированный
promise-объект, и через deferred-объект мы взаимодействуем с promise-объектом. Чтобы получить promise-объект, в самом конце функции используется следующее
выражение return deferred.promise
.
Если запрос увенчался успехом, то вызываем метод deferred.resolve(data.question);
. Этот метод сопоставляет данные с promise-объектом.
В результате вызов return deferred.promise
вернет нам загруженные данные.
Если запрос прошел неудачно, вызывается метод deferred.reject(status)
Контроллер у нас видоизменится следующим образом:
questApp.controller('QuestionController', function QuestionController($scope, dataService){ var promiseObj=dataService.getData(); promiseObj.then(function(value) { $scope.question=value; }); $scope.voteUp = function (answer){ answer.rate++; }; $scope.voteDown = function (answer){ answer.rate--; }; } )
Поскольку в вышеопределенном сервисе функция getData
возвращает promise-объект, который в свою очередь содержит все загруженные
данные, то мы можем просто присвоить эти данные: var promiseObj=dataService.getData();
В тоже время важно понимать, что теперь promiseObj
будет представлять не простой javascript-объект, а именно promise-объект,
что накладывает некоторые ограничения на его использование.
Чтобы получить чистый javascript-объект, можно использовать функцию promiseObj.then
, которая имеет следующий синтаксис:
then(successCallback, errorCallback, notifyCallback)
Параметр successCallback представляет функцию, которая выполняется при удачном завершении действия. Функция, передаваемая в качестве параметра
errorCallback
, наоборот, выполняется при неудачном завершении действия. И функция, представленная параметром
notifyCallback
, может выполняться в качестве индикатора выполнения действия.
В нашем случае мы использовали только первый параметр - функцию удачного выполнения действия, а в качестве параметра в нее передается уже непосредственно загруженный с сервера объект.
И в представлении index.html надо подключить созданный выше файл сервиса dataService.js:
<!doctype html> <html ng-app="questApp"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css/mystyles.css" /> </head> <body> <div ng-controller="QuestionController"> <div class="content"> <div class="quest"> <h3>{{question.text}}</h3> <p>{{question.author}} </p> <p><i>{{question.date}}</i></p> </div> <h3>Ответы</h3> <div class="answers"> <div ng-repeat="answer in question.answers | orderBy:sortparam" class="answer"> <div class="vote"> <a class="vote-up" ng-click="voteUp(answer)"></a> <span class="rate">{{answer.rate}}</span> <a class="vote-down" ng-click="voteDown(answer)"></a> </div> <b>{{answer.text}}</b> <p>{{answer.author}}</p> <p><i>{{answer.date}}</i></p> </div> </div> </div> <script src="js/lib/angular.min.js"></script> <script src="js/app.js"></script> <script src="js/dataService.js"></script> <script src="js/controllers/QuestionController.js"></script> </body> </html>