一、前言
在“AngularJS 项目开发技巧之图片预加载”一文中,自己曾经天真的认为提升服务端带宽就可以解决图片加载问题。但自己的想法错了,通过阅读破狼的书《AngularJS 深度剖析与最佳实践》,隐隐察觉到是自己的项目架构出现了问题。存在很多待优化的地方。其书中这样写到“如果在实例化控制器之前,需要准备一些特定数据,或者有条件的阻止进入路由,那么可以在 $routeProvider 中配置 Resolve 属性来解决。”
二、预载入 Resolve
使用预载入功能,开发者可以预先载入一系列依赖或者数据,然后注入到控制器中。在 ngRoute 中 resolve 选项可以允许开发者在路由到达前载入数据保证(promises)。在使用这个选项时比使用 angular-route 有更大的自由度。
预载入选项需要一个对象,这个对象的 key 即要注入到控制器的依赖,这个对象的 value 为需要被载入的 factory 服务。
如果传入的是字符串,angular-route 会试图匹配已经注册的服务。如果传入的是函数,该函数将会被注入,并且该函数返回的值便是控制器的依赖之一。如果该函数返回一个数据保证(promise),这个数据保证将在控制器被实例化前被预先载入并且数据会被注入到控制器中。
三、实现思路
将图片下载耗时操作做异步处理。图片下载代码如下:
try {
var data = {};
appCallServer($http, "9101", data,
//success function
function(data) {
console.log("9101:" + JSON.stringify(data.data));
var adpic = new Array;
for (var i = 0; i < data.data.length; i++) {
adpic[i] = data.data[i].url;
}
$scope.adpic = adpic;
return true;
},
// fail function
function(data) {
$ionicLoading.show({
template: "查询广告失败,请检查您的网络连接"
});
$timeout(function() {
$ionicLoading.hide();
}, 1200);
return false;
});
} catch (error) {
$scope.showAlert1("call:" + error.message);
return false;
}
复制代码
整理后的代码如下:
路由:
.state('tab.find_med', {
url: "/find_med",
views: {
'tab-find_med': {
templateUrl: "find_medicine.html",
controller: 'find_med_contrller',
resolve:{
adpic:function(){
var data = {};
appCallServer($http, "9101", data,
//success function
function(data) {
console.log("9101_resolve:" + JSON.stringify(data.data));
var adpic = new Array;
for (var i = 0; i < data.data.length; i++) {
adpic[i] = data.data[i].url;
}
return adpic;
},
// fail function
function(data) {
$ionicLoading.show({
template: "查询广告失败,请检查您的网络连接"
});
$timeout(function() {
$ionicLoading.hide();
}, 1200);
return false;
});
}
}
}
}
})
复制代码
控制器:
$scope.getadpic = function() {
$scope.adpic = adpic;
};
$scope.getadpic();
复制代码
执行程序,查看效果,提示如下错误:
unpr 全称是 Unknown Provider,也就是说没有找到注入的东西。
找了半天忽然醒悟了,resolve 中的对象只有在相应的控制器中才可以获取到,而自己之前是在别的控制器中添加的 resolve 对象,难怪总是报服务未注入的错误呢。正确的代码如下:
路由:
$stateProvider
.state('tab', {
url: "/tab",
templateUrl: "tabs.html",
controller: 'tabsCtrl',
resolve:{
adpic:function(){
return "www";
}
}
})
复制代码
控制器:
myCtrl.controller('tabsCtrl', function($scope, $rootScope, $http, $location,... $timeout, adpic) {
...
$scope.getadpic = function() {
console.log("adpic.........." + adpic);
};
$scope.getadpic();
}
复制代码
所以一定要掌握原理。不要茫然。
添加以上代码后,HBuilder 报如下错误:
通过参考网络文献,优化后的代码如下:
// 利用Factory单例特性创建服务
myModule.factory('myAdpicService',function($http, $q){
return {
getAdpic: function() {
var d = $q.defer();
var data = {};
appCallServer($http, "9101", data,
//success function
function(data) {
console.log("9101_resolve:" + JSON.stringify(data.data));
var adpic = new Array;
for (var i = 0; i < data.data.length; i++) {
adpic[i] = data.data[i].url;
}
console.log("adpic___________:" + adpic);
d.resolve(adpic);
},
// fail function
function(data) {
$ionicLoading.show({
template: "查询广告失败,请检查您的网络连接"
});
$timeout(function() {
$ionicLoading.hide();
}, 1200);
d.reject(data);
});
return d.promise;
}
}
});<span style="color: rgb(62, 75, 83); font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
复制代码
<span style="color:#ff0000;">$stateProvider
.state('tab', {
url: "/tab",
templateUrl: "tabs.html",
controller: 'tabsCtrl',
resolve:{
adpicSunny:function(myAdpicService) {
return myAdpicService.getAdpic();
}
}
}</span>
复制代码
控制器中的代码不做任何变化。
以上代码通过定义一个独立的 service 的方式来使用 resolve key,并且使用 service 来相应返回所需的数据(这种方式更容易测试)。并且对于较耗时的图片加载操作做异步处理。这与 Android 中的设计思想一致。至此,图片预加载问题成功解决。
有图有真相
评论