【问题标题】:Resolving a promise in a dependent AngularJS service解决依赖 AngularJS 服务中的承诺
【发布时间】:2014-10-11 00:30:45
【问题描述】:

我有一个在 Chrome 扩展中运行的简单 AngularJS 应用程序,它使用了存储 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() 方法之后触发,该方法在承诺解决时调用回调。任何最终指导表示赞赏。

【问题讨论】:

  • 您的意思是deferred.resolve(data); 而不是deferred.resolve(service);?您可以调用 restore 方法。并链接到UserService.restore().then((data)=>{ var token = data.api.token; })
  • 我将解析的data 值包含在更大的服务对象中。如果我在 APIService 中调用 restore 方法,那我不是必须将那个工厂的所有代码都放在 .then() 方法中吗?如果我还有其他要解决的承诺怎么办?
  • 下面的答案是正确的。你需要返回服务:app.factory('UserService', function($q, AppSettings) { .... return service;});

标签: angularjs angular-promise


【解决方案1】:

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

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
});

[编辑] 回答您的新问题:不要直接访问用户。在您的服务中创建一个新函数,例如返回承诺的 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;
  }
};

【讨论】:

  • 感谢您的意见,非常感谢。进行了您建议的更改,但仍未在 APIService 工厂中获得已解析的对象。用完整的更新代码更新上面的问题。
  • 最后一点数据 - 当我 console.log(UserService) 时,我可以看到所有属性...但是当我尝试使用点表示法(即 console.log(UserService.user))指定子属性时,我只获取__proto__ 属性。
【解决方案2】:

你没有从你的工厂返回一个对象。因此,当您尝试注入 UserService 参数时,它会给出 undefined ,因为您没有从 UserService 函数返回任何内容。

如果你返回 service 变量,我想你会得到你正在寻找的行为。

【讨论】:

  • 嗯,解析的data 对象不是我返回的服务对象本身吗?我上面有deferred.resolve(service); - 做出你建议的改变并没有改变结果。
猜你喜欢
  • 2013-08-05
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多