Angular中的在线/离线应用程序

4
我正在开发一个Angular应用程序,该应用程序对几个Web服务进行多次调用。我想开发一个离线组件,将某些Web服务结果缓存到LocalStorage中,并在连接离线时使用它们。
这部分相当简单,我遇到最大的问题是应用程序离线时如何进行逻辑分支。
以下是我的当前流程:
1.用户加载页面
2.Web服务调用按照通常方式处理
3.$http拦截器查找404错误并标记$rootScope.isOnline布尔标志以指示我们处于离线状态,否则如果没有404,则标记为在线。
我希望我的代码可以根据此标志进行分支,以便易于维护。因此,我考虑使用依赖注入来注入一个“在线”服务,该服务调用Web服务,或者注入一个“离线”服务,该服务与本地存储结果进行交互(如果存在)。
我是否可以基于在线/离线标志来进行依赖注入,以注入正确的服务?
.factory('AuthService', ['$rootScope', '$injector', function($rootScope, $injector) {
    if($rootScope.isOnline) {
        return $injector.get('OnlineAuthService');
    }
    else {
        return $injector.get('OfflineAuthService');
    }
}])

.service('OnlineAuthService', ['$rootScope', '$http', '$location', 'serviceEndpoint', 'securityEndpoint', 'organisationId', function ($rootScope, $http, $location, serviceEndpoint, securityEndpoint, organisationId) {
    this.ensureSession = function (data) {
        // Do some connection to the webservice
    };
}])

.service('OfflineAuthService', ['$rootScope', function ($rootScope) {
    this.ensureSession = function (data) {
        // Do some LocalStorage stuff
    };
}])

AuthService.ensureSession(data);

我遇到的问题是,在第一次调用我的web服务之前,$rootScope.isOnline没有被标记为离线,所以即使连接已经离线,依赖注入也会查看$rootScope.isOnline并注入OnlineAuthService。
这是否是在Angular中开发在线/离线应用程序的正确方式,还是有更好的方法?

基本上,我会通过在JavaScript中创建一个虚拟接口来处理这个问题,该接口可以同时使用两个服务,并在运行时确定要使用哪个服务。这样,在应用程序是否在线之前,该服务就可以被注入。我还会让它在内部处理初始化调用,以避免控制器尝试获取初始数据时出现竞争条件的情况。 - shaunhusain
这里有一个包含更详细代码的 plnkr:http://plnkr.co/edit/BXyZVU7uoKkJO4KQOs3R?p=info - joshschreuder
在初始化Angular之前,可以进行初始测试(不要自动初始化Angular),并将全局变量从测试传递到您的服务。当测试完成后调用Angular引导程序... 我觉得这就是@shaunhusain建议的内容。此外,我不确定在离线时是否会收到401错误? - charlietfl
这并不像一个全局变量,你可以给它一个非常独特的属性名,它不会污染太多,对我来说它节省了很多其他延迟编码。 - charlietfl
你需要在线才能获取404错误。如果你处于离线状态,$http请求将无法完成。在Angular上下文中此时无法确定错误是什么。 - craigb
显示剩余2条评论
1个回答

3
有许多方法可以实现此目的。看一下这个简化的plunker:http://plnkr.co/edit/CpiJaF480Mai050b63RC?p=preview。其思想是您有由服务返回的单例服务对象,但然后您将不同的函数方法复制为在线/离线更改。
还有许多其他方法可以做到这一点,例如添加间接层(创建一个服务,您可以从中请求当前活动服务)。 您不能仅使用angular注入来完成此操作,因为工厂和服务调用都将被调用一次且仅一次,并且只会为服务名称注册单个实例(它们不会在每次注入时被调用)。

这太棒了,完美地运行着,非常感谢您花时间给我提供一个例子! - joshschreuder
是的,这基本上就是我所说的,除了可能有一个服务,它只具有与最终实现所需的相同“接口”或函数。这里显示的示例是相同的东西,只是两个服务都具有可用的相同函数,并根据is online属性的当前状态切换要使用的服务。您可能还希望“AuthService”依赖于其他一些服务,以便在Online状态发生变化时进行数据“重新初始化”的调用。 - shaunhusain
这很好,但有没有一种更“Angular”的方式来实现相同的效果。即将registerOnlineOfflineService方法封装在工厂/提供程序中,而不是污染全局命名空间? - Matt Richards
你所说的全局命名空间是指$rootScope吗?如果是,那么可以将$watch更改为在服务上观察一个函数,而不是将isOnline放在作用域上。 - Daniel Tabuenca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接