【原】简述WEB项目前端脚本的一次重构历程,labJs,requireJs实践
重构前的状态:
大量的js代码混在繁多的Jsp文件中,对第三方的js库依赖也很杂乱。虽然在部分交互性较强的页面中,将js代码分离到了独立的js文件中,但是代码结构及依赖管理依然很乱。
不说新人来了无所适从,就是我自己看了,也会一头雾水。不是代码有多深奥,是看着实在太累。于是,一次重构工作开始了。
大量的js代码混在繁多的Jsp文件中,对第三方的js库依赖也很杂乱。虽然在部分交互性较强的页面中,将js代码分离到了独立的js文件中,但是代码结构及依赖管理依然很乱。
不说新人来了无所适从,就是我自己看了,也会一头雾水。不是代码有多深奥,是看着实在太累。于是,一次重构工作开始了。
重构中的事情:
1、首先,整个项目的页脚页头都有用到一些js和js库,这些具有共性的js先抽离到一个独立的head.js与foot.js中,放到include文件夹下。
2、对于公用的js库,如jquery,blockUI,jquery-template,日历控件等,先通过<script>标签依次放置于foot.jsp中。
3、对于强交互的页面,将其js文件放在include平级的目录下,以该项目名命名, 如app。
4、第一步的脚本分离工作就完成了,但这只是万里长征的第一步,接下来就需要管理好这些依赖和合理组织其中的代码结构了。
5、对于js库的管理,可以用lab.js或require.js,在本次重构中,两者都使用了。由于从jsp重分离出来的js代码没有良好的组织,其对第三方库的依赖也很难一时理清。
再者,重构之事,有时间上的要求,只要分阶段走了。先保证js分离后能够不影响项目正常运行,然后再一步步合理优化代码。
6、于是使用了lab.js,理由是可以按原页面要求的加载顺序来加载第三方js库,这样可以确保抽离出来的js能在lab.js加载相关库后,正确的运行。
foot.jsp中定义了全局变量
7、在强交互的页面,使用require.js来管理本页面所用到的js,异步加载,通过初始化函数执行各种定时器启动、事件绑定等。而初始化函数所需要的参数,
在jsp中预初始化,供js使用。
app.jsp中
8、接下来就是这个应用的js代码重构了,充分利用requireJs良好的模块管理机制,让代码结构更合理,维护更便利,可读性更强。
main.js中
9、jsonUtil代码:
小结:当然重构并不是三言两句就能说清楚了,不过这一步走过来后,现在无论前端性能,还是代码质量、管理,都有了质的提升!
1、首先,整个项目的页脚页头都有用到一些js和js库,这些具有共性的js先抽离到一个独立的head.js与foot.js中,放到include文件夹下。
2、对于公用的js库,如jquery,blockUI,jquery-template,日历控件等,先通过<script>标签依次放置于foot.jsp中。
3、对于强交互的页面,将其js文件放在include平级的目录下,以该项目名命名, 如app。
4、第一步的脚本分离工作就完成了,但这只是万里长征的第一步,接下来就需要管理好这些依赖和合理组织其中的代码结构了。
5、对于js库的管理,可以用lab.js或require.js,在本次重构中,两者都使用了。由于从jsp重分离出来的js代码没有良好的组织,其对第三方库的依赖也很难一时理清。
再者,重构之事,有时间上的要求,只要分阶段走了。先保证js分离后能够不影响项目正常运行,然后再一步步合理优化代码。
6、于是使用了lab.js,理由是可以按原页面要求的加载顺序来加载第三方js库,这样可以确保抽离出来的js能在lab.js加载相关库后,正确的运行。
foot.jsp中定义了全局变量
1
<
script type
=
"
text/javascript
"
>
2 var username = " ${loginUser.username} " ;
3 var version = " ${version} " ;
4 </ script >
5 < script type = " text/javascript " src = " ${staticJsRoot}/common/LAB.min.js?${version} " ></ script >
6 < script type = " text/javascript " >
7 // 供其他包含页面使用,确保在一个依赖请求链条内
8 $LAB = $LAB.script(LOCATION.js + " /common/jquery-1.6.1.min.js? " + version).wait() // 确保顺序加载
9 .script(LOCATION.js + " /common/include/head.js? " + version).wait()
10 .script(LOCATION.js + " /common/include/foot.js? " + version).wait( function (){
11 // 执行全局初始化,如异步登录检测等
12 loadFootReady();
13 });
14 </ script >
2 var username = " ${loginUser.username} " ;
3 var version = " ${version} " ;
4 </ script >
5 < script type = " text/javascript " src = " ${staticJsRoot}/common/LAB.min.js?${version} " ></ script >
6 < script type = " text/javascript " >
7 // 供其他包含页面使用,确保在一个依赖请求链条内
8 $LAB = $LAB.script(LOCATION.js + " /common/jquery-1.6.1.min.js? " + version).wait() // 确保顺序加载
9 .script(LOCATION.js + " /common/include/head.js? " + version).wait()
10 .script(LOCATION.js + " /common/include/foot.js? " + version).wait( function (){
11 // 执行全局初始化,如异步登录检测等
12 loadFootReady();
13 });
14 </ script >
7、在强交互的页面,使用require.js来管理本页面所用到的js,异步加载,通过初始化函数执行各种定时器启动、事件绑定等。而初始化函数所需要的参数,
在jsp中预初始化,供js使用。
app.jsp中
1
2 var initParams = {
3 maps : {
4 aIds : []
5 } ,
6 aid : ' ${aid} ' ,
7 bid : ' ${bid} ' ,
8 cid : ' ${cid} '
9 };
10
11 < c : forEach items = " ${list} " var = " obj " varStatus = " sta " >
12 < c : choose >
13 < c : when test = " ${obj.type==1} " >
14 initParams . maps . aIds . push(obj . aId);
15 </ c : when >
16 </ c : choose >
17 </ c : forEach >
18
19 // 使用labjs继续加载本页面需要用到的js库
20 $LAB . script(LOCATION . js + " /common/jquery.tmpl.js? " + version) . wait()
21 . script(LOCATION . js + " /common/audio/jquery.jmp3.js? " + version) . wait()
22 ;
23 </ script >
24 <!-- 使用require . js加载这个应用的js -->
25 < script data - main = " ${staticJsRoot}/apps/view/main.js " src = " ${staticJsRoot}/common/require.js " ></ script >
<
script type
=
"
text/javascript
"
>
//
需要用到的初始化参数
2 var initParams = {
3 maps : {
4 aIds : []
5 } ,
6 aid : ' ${aid} ' ,
7 bid : ' ${bid} ' ,
8 cid : ' ${cid} '
9 };
10
11 < c : forEach items = " ${list} " var = " obj " varStatus = " sta " >
12 < c : choose >
13 < c : when test = " ${obj.type==1} " >
14 initParams . maps . aIds . push(obj . aId);
15 </ c : when >
16 </ c : choose >
17 </ c : forEach >
18
19 // 使用labjs继续加载本页面需要用到的js库
20 $LAB . script(LOCATION . js + " /common/jquery.tmpl.js? " + version) . wait()
21 . script(LOCATION . js + " /common/audio/jquery.jmp3.js? " + version) . wait()
22 ;
23 </ script >
24 <!-- 使用require . js加载这个应用的js -->
25 < script data - main = " ${staticJsRoot}/apps/view/main.js " src = " ${staticJsRoot}/common/require.js " ></ script >
8、接下来就是这个应用的js代码重构了,充分利用requireJs良好的模块管理机制,让代码结构更合理,维护更便利,可读性更强。
main.js中
1
//
首先定义好要用到的全局配置
2 requirejs.config({
3 baseUrl : LOCATION.app,
4 paths: {
5 " util " : " utils/util " ,
6 " jsonUtil " : " utils/jsonUtil " ,
7 " domUtil " : " utils/domUtil " ,
8 " eventUtil " : " utils/eventUtil " ,
9 " bUtil " : " utils/bUtil " ,
10 " cUtil " : " utils/cUtil " ,
11 " dUtil " : " utils/dUtil " ,
12
13 " service " : " service/service " ,
14 " aService " : " service/aService " ,
15 " bService " : " service/bService "
16 }
17 });
18
19 // 然后加载应用的各种组件,并执行函数调用,run起来
20 requirejs([ " config " ,
21 " service " ,
22 " util " ,
23 " template " ,
24 " loader " ,
25 " public " ], function (config, service, util, tmpl){
26 window.MyApp = config;
27 MyApp.tmpl = tmpl;
28 //使用jsonUtil,将各种util combine成util.js,将各种service combine成service.js
29 util.combine(MyApp, service);
30 util.combine(MyApp, util);
31
32 MyApp.ready();
33 }
34 );
2 requirejs.config({
3 baseUrl : LOCATION.app,
4 paths: {
5 " util " : " utils/util " ,
6 " jsonUtil " : " utils/jsonUtil " ,
7 " domUtil " : " utils/domUtil " ,
8 " eventUtil " : " utils/eventUtil " ,
9 " bUtil " : " utils/bUtil " ,
10 " cUtil " : " utils/cUtil " ,
11 " dUtil " : " utils/dUtil " ,
12
13 " service " : " service/service " ,
14 " aService " : " service/aService " ,
15 " bService " : " service/bService "
16 }
17 });
18
19 // 然后加载应用的各种组件,并执行函数调用,run起来
20 requirejs([ " config " ,
21 " service " ,
22 " util " ,
23 " template " ,
24 " loader " ,
25 " public " ], function (config, service, util, tmpl){
26 window.MyApp = config;
27 MyApp.tmpl = tmpl;
28 //使用jsonUtil,将各种util combine成util.js,将各种service combine成service.js
29 util.combine(MyApp, service);
30 util.combine(MyApp, util);
31
32 MyApp.ready();
33 }
34 );
9、jsonUtil代码:
1
define(
function
(){
2 return {
3 /*
4 * util包里的核心工具类
5 * 将json2中的key-value添加到json1中,
6 * 如果json2为空或未定义,则将json1添加到调用者中
7 * @author idu
8 */
9 combine: function (json1, json2){
10 if ( ! json2) {
11 var temp = json1;
12 json1 = this ;
13 json2 = temp;
14 }
15
16 for ( var i in json2){
17 json1[i + "" ] = json2[i];
18 }
19
20 return json1;
21 }
22 };
23 });
24
2 return {
3 /*
4 * util包里的核心工具类
5 * 将json2中的key-value添加到json1中,
6 * 如果json2为空或未定义,则将json1添加到调用者中
7 * @author idu
8 */
9 combine: function (json1, json2){
10 if ( ! json2) {
11 var temp = json1;
12 json1 = this ;
13 json2 = temp;
14 }
15
16 for ( var i in json2){
17 json1[i + "" ] = json2[i];
18 }
19
20 return json1;
21 }
22 };
23 });
24
小结:当然重构并不是三言两句就能说清楚了,不过这一步走过来后,现在无论前端性能,还是代码质量、管理,都有了质的提升!