Используйте Promise и службу вместе в Angular
Мой вопрос основан на в этом разделе в группе Angular Google.
Я хочу предоставить службу, которая хранит некоторые базовые данные, извлеченные из бэкэнд через $http, тогда мне нужно только один раз получить эти данные. например,
var load = function() {
return $http.get(...).then(function(data) {
return data.user;
});
};
module.factory("userProvider", function() {
var user;
var getUser = function() {
if(!user) {
load().then(function(data) {
user = data;
});
}
return user;
};
return {
getUser : getUser
}
});
module.controller("UserController", ["userProvider", function UserController("userProvider") {
var user = userProvider.getUser();
// do something with user
}]);
Проблема в том, что цепочка обещаний заканчивается в userProvider, но не в контроллере, поэтому пользователь undefined при первом использовании этого контроллера, поскольку данные не были возвращены.
Как я могу использовать такую службу хранения и правильно вернуть данные? Спасибо!
Ответы
Ответ 1
Вы можете просто создать свое собственное обещание. Вот модифицированный код:
module.factory( "userProvider", function( $q ) {
// A place to hold the user so we only need fetch it once.
var user;
function getUser() {
// If we've already cached it, return that one.
// But return a promise version so it consistent across invocations
if ( angular.isDefined( user ) ) return $q.when( user );
// Otherwise, let get it the first time and save it for later.
return whateverFunctionGetsTheUserTheFirstTime()
.then( function( data ) {
user = data;
return user;
});
};
// The public API
return {
getUser: getUser()
};
});
Обновление: Решение ниже от @yohairosen является отличным для многих обстоятельств, но не для всех. В некоторых случаях мы хотели бы только кэшировать успешный результат, как я это сделал. Если, например, отказ этого запроса указывает, что пользователю необходимо сначала войти в систему, мы не захотим следующего вызова (предположительно после входа в систему), чтобы доставить сбой кэширования. В тех случаях, когда метод не обязательно согласован с призывом к вызову при любых обстоятельствах, этот метод лучше; во всех остальных случаях решение @yohairosen проще и рекомендуется.
Ответ 2
Немного накладных расходов, чтобы создать свое собственное обещание, angular $http создает для вас все равно. То, что вы ищете, - это кеширование, а http может обрабатывать его для вас, передавая кеш: true для вызова службы.
Итак, вы можете просто сделать что-то вроде этого:
module.factory("userProvider", function() {
var getUser = function() {
return $http.get(..., {cache:true}).then(function(data) {
return data.user;
});
return {
getUser : getUser
}
});