AngularJS使用$ rootScope作为数据存储

时间:2013-05-24 15:58:24

标签: angularjs

我对AngularJS应用程序有一个想法,如果AngularJS社区认为可以这样做,我很好奇......

简而言之,我正在连接数据API并在页面上显示我的结果。我创建了一个角度服务,在$ rootScope.DataStore上创建数据存储。我还有一个服务方法,它使用API​​端点返回的数据更新DataStore。如果我使用DataStore.update('products')从我的控制器内部请求“products”API端点,这将使用我的产品数据更新$ rootScope.DataStore.products。现在,在view / partial中,我需要做的就是用ng-repeat =“DataStore.products中的产品”来显示我的数据,并且我在哪个控制器范围并不重要。所以,本质上我的DataStore是我唯一的事实来源。

我觉得从这种方法中获得的东西很容易遵循语义和最小的控制器编码。因此,无论何时更新DataStore,任何绑定到DataStore的东西都会得到更新。

这会对$ rootScope摘要周期造成太大负担,还是这只是一种奇怪的方法呢?或者它是一个非常棒的方式? :)欢迎任何评论。

5 个答案:

答案 0 :(得分:88)

此问题在此处引用的AngularJS FAQ中解决:

  

偶尔会有一些您想要全局化的数据   整个应用程序。对于这些,您可以注入$ rootScope 并设置值   它像任何其他范围。由于范围继承自根范围,   这些值可用于附加的表达式   像ng-show这样的指令就像本地$ scope的值一样。

似乎团队确实鼓励以这种方式使用$rootScope,但需要注意:

  

当然,全球状态很糟糕,你应该谨慎使用$ rootScope,   就像你希望用任何语言的全局变量一样。   特别是,不要将它用于代码,只用于数据。如果你很想   把一个函数放在$ rootScope上,把它放在一个几乎总是更好   可以在需要的地方注入,更容易注入的服务   测试

     

相反,不要创建一个生活中唯一目的的服务   存储并返回数据位。

这不会对$digest周期(实现基本脏检查以测试数据突变)施加太多负载,这并不是一种奇怪的处理方式。

编辑:有关性能的详细信息,请参阅Misko(AngularJS dev)的答案,在此处:How does data binding work in AngularJS?请特别注意性能部分。

答案 1 :(得分:32)

为了安抚所有各方,为什么不使用$ cacheFactory。这允许数据请求服务是无状态的,基本上只是一个getter和setter。我承认将数据保存在$ rootScope上或作为服务中的属性很方便,但感觉不对。使用$ cacheFactory也很容易。

首先创建一个缓存服务:

angular.module('CacheService', ['ng'])
    .factory('CacheService', function($cacheFactory) {
    return $cacheFactory('CacheService');
});

在你的app.js中加入js文件,然后将其注入你的app声明:

var MyApp = angular.module('MyApp', ['CacheService']);

在服务中注入它,像这样使用它:

'use strict'

MyApp.factory('HackerNewsService', function(CacheService) {
    return {
        getNews: function(key) {
            var news = CacheService.get(key);

            if(news) {
                return news;
            }

            return null;
        },
        setNews: function(key, value) {
            CacheService.put(key, value);
        },
        clearNews: function(key) {
            CacheService.put(key, '');
        }
    };
});

现在你要做的就是在控制器中注入HackerNewsService,并通过调用我们在其上创建的方法来使用它。例如:

HackerNewsService.setNews('myArticle', {headline: 'My Article', body: 'This is the body'});
$scope.article = HackerNewsService.getNews('myArticle');

答案 2 :(得分:8)

我的经验是使用$ rootScope存储我的应用程序中所有ngView所共有的数据模型部分,这是最方便的方法。

<div>{{mymodel.property}}</div>

对我来说比

更具可读性和更短
<div>{{getPropertyModel()}}</div>

使用javascript

app.factory('MyModel', function(){
    return {
        getModel: function() { ... },
        setModel: function(m) { ... },
    }
});

app.controller('ctrl', ['$scope', 'MyModel', function($scope, MyModel){
    $scope.getPropertModel = function() {
        return MyModel.getModel().property;
    };
}]);

如果使用服务或cachefactory,则html模板中对模型的每次访问都会成为一个函数,与访问rootScope的属性相比,它的可读性较差。使用$ rootScope可以减少代码,从而减少错误,减少测试次数。

当然,只有所有ngView的公共部分都存储在$ rootScope中。模型的其余部分存储在本地$ scope中。

对函数的监视也比对象属性慢。因此,性能方面,$ rootScope也更好。

答案 3 :(得分:0)

我想我不确定你为什么需要使用rootScope?服务实例的生命周期也是整个应用程序,因此您使用的任何数据模式/语义也可以隐藏在服务本身中,并且它将在控制器之间共享。然而,这些方法中的任何一种都不能像使用本地存储那样在刷新中存活。

其余部分听起来像是一种懒惰的加载方法。服务是唯一“知道”数据是否已从远程加载并在已缓存时返回并缓存并返回的情况(如果不是)?如果我理解这部分是一个很好的模式。

编辑: 在这里,我采用了类似的延迟加载方法,注意缓存只是在服务本身:

angular.module('HN_Reddit_Mashup.Services', [])
    .factory('HackerNews', function($http) {
        var HackerNewsCache = {};
        return {
            get: function(url) {
                return HackerNewsCache[url] ||
                    (HackerNewsCache[url] = $http.jsonp("http://api.thriftdb.com/api.hnsearch.com/items/_search?q=" + url +     "&callback=JSON_CALLBACK"));
            },                
        };
    })

答案 4 :(得分:0)

我只是面临同样的问题,在我看来,将它存储在全球可用的“位置”是正确的方法,但$ rootScope不是理想的地方。

我刚刚研究了这个,而不是将数据存储在$ rootScope上,您可以考虑使用“服务”来管理您的数据/单独的关注点,如此处所述(特别是最后一个代码示例):{{ 3}}

然后在使用该方法创建的“服务”中,无论是将数据保存在内存中,还是将文件保存在http://joelhooks.com/blog/2013/04/24/modeling-data-and-state-in-your-angularjs-application/中(如localstorage所提及的),和/或保存到数据库中(例如,通过AJAX),可满足您的应用需求。它还意味着可以根据需要单独更改存储数据的方式。