我有一个AngularJS服务,我想使用一些异步数据进行初始化。像这样:
myModule.service('MyService', function($http) { var myData = null; $http.get('data.json').success(function (data) { myData = data; }); return { setData: function (data) { myData = data; }, doStuff: function () { return myData.getSomeData(); } }; });
显然,这是行不通的,因为如果doStuff()在myData返回之前尝试进行调用,我将得到一个空指针异常。据我从阅读这里和这里提出的其他一些问题中所知道的,我有一些选择,但是它们似乎都不是很干净(也许我错过了一些东西):
doStuff()
myData
安装服务“运行”
设置我的应用程序时,请执行以下操作:
myApp.run(function ($http, MyService) { $http.get('data.json').success(function (data) { MyService.setData(data); }); });
然后我的服务将如下所示:
myModule.service('MyService', function() { var myData = null; return { setData: function (data) { myData = data; }, doStuff: function () { return myData.getSomeData(); } }; });
这有时会起作用,但是如果异步数据恰好比初始化所有东西花费的时间更长,则在我调用时会得到一个空指针异常 doStuff()
使用承诺对象
这可能会起作用。我调用MyService的所有地方唯一的缺点是,我必须知道doStuff()返回了一个promise,所有代码都必须与我们then交互才能与promise交互。我宁愿等到myData返回之后再加载我的应用程序。
then
手动引导
angular.element(document).ready(function() { $.getJSON("data.json", function (data) { // can't initialize the data here because the service doesn't exist yet angular.bootstrap(document); // too late to initialize here because something may have already // tried to call doStuff() and would have got a null pointer exception }); });
全局Java语言Var 我可以将JSON直接发送到全局Java语言变量:
HTML:
<script type="text/javascript" src="data.js"></script>
data.js:
var dataForMyService = { // myData here };
然后在初始化时可用MyService:
MyService
myModule.service('MyService', function() { var myData = dataForMyService; return { doStuff: function () { return myData.getSomeData(); } }; });
这也可以,但是我有一个全局的javascript变量,它闻起来不好。
这些是我唯一的选择吗?这些选择之一比其他选择更好吗?我知道这是一个很长的问题,但我想表明我已尝试探索所有选择。任何指导将不胜感激。
你看了$routeProvider.when('/path',{ resolve:{...}吗?它可以使诺言方法更加简洁:
$routeProvider.when('/path',{ resolve:{...}
在您的服务中兑现承诺:
app.service('MyService', function($http) { var myData = null; var promise = $http.get('data.json').success(function (data) { myData = data; }); return { promise:promise, setData: function (data) { myData = data; }, doStuff: function () { return myData;//.getSomeData(); } }; });
添加resolve到您的路由配置:
resolve
app.config(function($routeProvider){ $routeProvider .when('/',{controller:'MainCtrl', template:'<div>From MyService:<pre>{{data | json}}</pre></div>', resolve:{ 'MyServiceData':function(MyService){ // MyServiceData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service return MyService.promise; } }}) }):
解决所有依赖关系之前,不会实例化您的控制器:
app.controller('MainCtrl', function($scope,MyService) { console.log('Promise is now resolved: '+MyService.doStuff().data) $scope.data = MyService.doStuff(); });
我在plnkr上做了一个例子:http ://plnkr.co/edit/GKg21XH0RwCMEQGUdZKH?p=preview