Angular+Requirejs实现模块按需加载

时间:2023-02-09 19:22:51

Aangular作为前端开发利器,被广大前端研发人员所熟知,本人从接触到现在快有两年时间了,负责和Angular相关的产品也有10几个,有业务逻辑复杂的,有业务简单的,业务简单架构就简单,怎么搭建都行,只要开发效率快,维护成本低就可以,但是针对于复杂的业务逻辑,就会遇到很多问题,如果在初始化的时候进行互相依赖加载,那样首次加载,如果使用angular-ui-router进行路由管理,就需要将所有state依赖的的controller文件全部加载进来,由于业务复杂,controller文件有可能会有很多,还不包括资源类的请求,这样首次加载会非常缓慢,影响用户体验。
为了解决首次加载问题,首次加载只加载公共资源,并且将业务模块进行细化,每个路由状态对应相应的业务模块,首次加载只提供给用户的某一个模块,让首次加载更加轻量化,其他业务模块在路由状态切换时进行动态加载,也就是所谓的按需加载,最终选择方引用第三方组件angularAMD和ct-ui-router-extras来解决。
angularAMD是实现angular的controller、service异步加载的核心组件,ct-ui-router-extras是ui-router的扩展插件, 进行状态管理,它主要是监听路由状态变化,具体文档大家可以戳这里:http://christopherthielen.github.io/ui-router-extras/#/home,主要是用到其中的futureState,在应用启动时候在config中对futureState进行初始化,将所有的路由状态配置到 futureState中,在路由发生变化时,先判断路由状态是否存在,如果不存在,则会调用初始化时注册的angularAMD的ngload服务,实现对模块以及依赖的异步加载。

初始化配置

config(['$futureStateProvider','$locationProvider',function($futureStateProvider,$locationProvider) {
var loadAndRegisterFutureStates = ['$http','lazyHerper',function ($http,lazyHerper) {
return lazyHerper.getLazyModuleCfg().then(function(moduleCfg){
angular.forEach(moduleCfg, function (cfg) {
$futureStateProvider.futureState(cfg);
});
});
}];

$futureStateProvider.stateFactory('ngload', ngloadStateFactory); // register AngularAMD ngload state factory
$futureStateProvider.stateFactory('iframe', iframeStateFactory); // register silly iframe state factory
$futureStateProvider.stateFactory('requireCtrl', requireCtrlStateFactory); // Register state factory that registers controller via eval.

$futureStateProvider.addResolve(loadAndRegisterFutureStates);
}])

这个函数是按需加载的核心

function ngloadStateFactory($q, futureState) {
var ngloadDeferred = $q.defer();
require([ 'ngload!' + futureState.src , 'ngload', 'angularAMD'],
function ngloadCallback(result, ngload, angularAMD) {
angularAMD.processQueue();
ngloadDeferred.resolve(undefined);
});
return ngloadDeferred.promise;
}

懒加载路由配置文件
define([],function(){
return {
lazyCfg:[
{
“stateName”:”app.cloud”,
“urlPrefix”:”/cloud”,
“type”:”ngload”,
“src”:globalConfig.appPath+’cloud/app-cloud.module.js’
},
{
“stateName”:”app.network”,
“urlPrefix”:”/network”,
“type”:”ngload”,
“src”:globalConfig.appPath+’network/app-network.module.js’
}
]
}
})

这里有一点需要注意,就是在模块按需夹在的时候需要对响应的服务进行动态注册,否则会提示不能注册angular相关服务。
define([“utils/depResolve”],function(depResolve){
return function(routerConfig){
var self = this;
this.config([‘ stateProvider, urlRouterProvider’,
locationProvider, controllerProvider’,
compileProvider, filterProvider’,
provide,function( stateProvider, urlRouterProvider, locationProvider, controllerProvider, compileProvider, filterProvider, provide){
//多模块的异步加载时,无法满足模块controller、directive、service等动态定义
//也就是说在加载完module文件后,再动态加载相关的controller、directive、service等时
//提示controller、directive、service等未定义
//所以必须在加载module文件同时在模块的config中注入相应的provider服务进行动态注册。
self.controller = controllerProvider.register;self.directive= compileProvider.directive;
self.filter = filterProvider.register;self.factory= provide.factory;
self.service = $provide.service;

        }
]);
}

})

以上是本人对angular开发的一些总结,希望对有需求的童鞋有一些帮助,有问题可以评论,大家互相讨论学习。demo地址是:https://github.com/mazhaohai/angular-lazyload.git