AngularJS Ui-router多控制器复用resolve结果,避免重复请求数据
你这个重复请求的问题在ui-router场景下有几个很实用的解决办法,不用非得折腾run函数或者复杂的继承逻辑,我给你梳理几个靠谱的方案:
看你的视图结构,test2是嵌套在test1模板里的子视图,这种情况下完全可以把共享的getData resolve定义在父状态testsPage的根级别,而不是每个视图各自单独定义。这样整个状态加载时只会执行一次resolve逻辑,两个视图的控制器都能直接注入已经获取好的数据:
.state('testsPage', { url: "/", // 把getData移到这里,整个状态下只执行一次 resolve: { getData: function(testService) { return testService.getdata(); } }, views: { 'test1': { templateUrl: 'public/src/test2.html', controller: 'test2Controller', controllerAs: 'vm' // 这里不再需要单独写resolve }, 'test2': { templateUrl: 'public/src/test1.html', controller: 'test1Controller', controllerAs: 'vm' // 这里也不用写resolve } } })
之后你的两个控制器直接注入getData就能用,不用再处理服务调用:
// test2Controller示例 angular.module('yourApp').controller('test2Controller', function(getData) { var vm = this; vm.data = getData; // 其他控制器逻辑... }); // test1Controller同理 angular.module('yourApp').controller('test1Controller', function(getData) { var vm = this; vm.data = getData; });
这样就只会发起一次请求,因为resolve在状态初始化时只执行一次,所有关联的控制器共享这个结果,完美解决重复请求的问题。
如果不想改动路由结构,也可以利用AngularJS服务是单例的特性,在testService里缓存getdata的请求结果。这样不管你调用多少次testService.getdata(),第二次及以后都会直接返回缓存的结果,不会发起新的请求:
angular.module('yourApp').service('testService', function($http, $q) { var cachedData = null; this.getdata = function() { // 如果已经有缓存,直接返回已解决的Promise if (cachedData) { return $q.resolve(cachedData); } // 没有缓存就发起请求,并存入缓存 return $http.get('/your-api-endpoint') .then(function(response) { cachedData = response.data; return cachedData; }); }; });
这个方法的好处是通用性强——哪怕其他状态或控制器需要这份数据,也能直接复用缓存,不用重复请求,代码耦合度也很低。
你之前尝试的继承思路是对的,但可以调整得更简洁:让基础控制器负责接收resolve来的数据,子控制器直接继承基础控制器,不用自己注入服务。比如:
// 基础控制器,只处理共享数据 angular.module('yourApp').controller('baseController', function(getData) { var vm = this; vm.sharedData = getData; }); // test2Controller继承基础控制器 angular.module('yourApp').controller('test2Controller', function($controller) { var vm = this; // 继承baseController的属性和方法 angular.extend(vm, $controller('baseController', {$scope: vm})); // 这里写test2Controller独有的逻辑 }); // test1Controller同理继承
不过这个方案的前提是getData已经在父状态的resolve里定义好了(不然还是会重复调用服务),本质上是方案1的补充优化。
完全没必要把数据获取逻辑移到run函数里。run函数是用来做全局初始化配置的,把数据放在那里不仅会让代码耦合度变高,还得通过$rootScope传递数据,这不是AngularJS推荐的实践方式。上面的两个方案(父状态resolve或service缓存)都比这种方式更清晰、更符合框架设计模式。
内容的提问来源于stack exchange,提问作者Tuz

