解决依赖AngularJS服务中的promise

时间:2014-10-09 20:08:48

标签: angularjs angular-promise

我在Chrome扩展程序中运行了一个简单的AngularJS应用程序,该应用程序使用了Storage API。存在异常的存储问题;我已经将存储抽象为“UserService”,它将数据设置并作为工厂获取:

app.factory('UserService', 
  function($q, AppSettings) {
    var defaults = {
      api: {
        token: AppSettings.environments[1].api.token
      },
      email: ''
    };
    var service = {
      user: {},
      save: function() {
        chrome.storage.sync.set({'user': angular.toJson(service.user)});        
      },
      restore: function() {
        var deferred = $q.defer();
        chrome.storage.sync.get('user', function(data) {
          if(!data) {
            chrome.storage.sync.set({'user': defaults});
            service.user = defaults;
          } else {
            service.user = angular.fromJson(data.user); 
          }
          deferred.resolve(service);
        });
        return deferred.promise;
      }
    };

    // set the defaults
    service.restore().then(function(data) {
      console.log(data);
      return data;
    });
});

上面的console.log()调用会按预期转储数据。但是,当我在其他工厂中包含UserService时(我有一个使用特定于用户的API令牌的APIService),UserService参数在下面的代码中被标记为“未定义”:

app.factory('APIService', 
  function($resource, $http, UserService, AppSettings) {
    var token = UserService.user.api.token;
    ...
});

我确信在整个应用程序中消费已解决的承诺方面,我并没有完全掌握Angular承诺模式。

更新代码:

app.factory('UserService', 
  function($q, AppSettings) {
    var defaults = {
      api: {
        token: AppSettings.environments[1].api.token
      },
      email: ''
    };
    var service = {
      user: {},
      save: function() {
        chrome.storage.sync.set({'user': angular.toJson(service.user)});        
      },
      restore: function() {
        var deferred = $q.defer();
        chrome.storage.sync.get('user', function(data) {
          if(!data) {
            chrome.storage.sync.set({'user': defaults});
            service.user = defaults;
          } else {
            service.user = angular.fromJson(data.user); 
          }
          deferred.resolve(service.user);
        });
        return deferred.promise;
      }
    };

    // set the defaults
    service.restore().then(function(data) {
      console.log(data);
      return data;
    });

    return service;
});

编辑/其他信息:

好的,靠近。已经重构,以便我正确地返回对象,但现在的问题是,当APIService被创建并尝试使用UserService对象的属性时,它们根本就不存在,因为它们仅在解析异步还原方法后创建。因此,不可能访问UserService.user.api.token属性,因为此时它不存在,所以问题是,如果在那时我不需要它,如何在需要时获取APIService中的数据?我试图避免将APIService的全部内容放入一个回调中,该回调在一个假定的新UserService.get()方法之后触发,该方法在解析promise时调用回调。任何最终指导都表示赞赏。

2 个答案:

答案 0 :(得分:2)

您没有从工厂退回物品。因此,当您尝试注入UserService参数时,它会提供undefined,因为您还没有从UserService函数返回任何内容。

如果您退回service变量,我认为您将获得您正在寻找的行为。

答案 1 :(得分:2)

您的服务有误。请看我的修复:

app.factory('UserService', 
function($q, AppSettings) {
 var defaults = {
  api: {
    token: AppSettings.environments[1].api.token
  },
  email: ''
};
var service = {
  user: {},
  save: function() {
    chrome.storage.sync.set({'user': angular.toJson(service.user)});        
  },
  restore: function() {
    var deferred = $q.defer();
    chrome.storage.sync.get('user', function(data) {
      if(!data) {
        chrome.storage.sync.set({'user': defaults});
        service.user = defaults;
      } else {
        service.user = angular.fromJson(data.user); 
      }
      deferred.resolve(service.user); // <--- return the user in here
    });
    return deferred.promise;
  }
};

// set the defaults
service.restore().then(function(data) {
  console.log(data);
  return data;
});

return service; // <--- return the service to be used injected when injected
});

[编辑] 回答你的新问题:不要直接访问用户。在您的服务中创建一个新函数,如返回promise的getUser()。在该函数中,如果用户已经被检索,则返回该用户,否则返回restore()函数:

var service = {
  user: null,
  getUser: function() {
       if (service.user)
       {
           var deferred = $q.defer();
           deferred.resolve(service.user);
           return deferred.promise;
       }
       else
           return service.restore();

  },
  save: function() {
    chrome.storage.sync.set({'user': angular.toJson(service.user)});        
  },
  restore: function() {
    var deferred = $q.defer();
    chrome.storage.sync.get('user', function(data) {
      if(!data) {
        chrome.storage.sync.set({'user': defaults});
        service.user = defaults;
      } else {
        service.user = angular.fromJson(data.user); 
      }
      deferred.resolve(service.user); // <--- return the user in here
    });
    return deferred.promise;
  }
};