面向未来的重构1. ⾯面向未来的“重构”
kejun
hikejun.com | twitter/weibo: @kejunz | douban.com/people/listenpro
http://www.flickr.com/photos/fernando_alda/6399170943/in/set-72157628144032827
Sunday, November 4, 12
3. “重构”观念的理解
第一层“重构”是指基于Web标准 发网站
Sunday, November 4, 12
4. “重构”观念的理解
第一层“重构”是指基于Web标准 发网站
第二层“重构”的目标是实现代码 用、⻚页面性能和可维护性
Sunday, November 4, 12
5. “重构”观念的理解
第一层“重构”是指基于Web标准 发网站
第二层“重构”的目标是实现代码 用、⻚页面性能和可维护性
第三层“重构”的目标是实现 活性和响应性
Sunday, November 4, 12
6. “重构”观念的理解
第一层“重构”是指基于Web标准 发网站
第二层“重构”的目标是实现代码 用、⻚页面性能和可维护性
第三层“重构”的目标是实现 活性和响应性
前 个层次是解决过去和当前的问题,第三个层次是解决未来问题的基础
Sunday, November 4, 12
8. 迭代频率
C类
B类
A类
生命周期
Sunday, November 4, 12
9. 迭代频率
C类 活性
B类 易维护性
A类 效率
生命周期
Sunday, November 4, 12
10. 现象分析
⻚页面生命周期⻓长、迭代频繁的情况最容易产生代码冗余
未用到 用到 扫描⻚页面数 Last-Modified
weibo frame.css 1686 485 25 11/02
index.css 299 38 25 10/10
A_index.css 3203 384 25 11/02
douban _init_.css 163 180 47 10/10
_all.css 256 118 47 10/17
douban.css 2011 360 47 11/01
Sunday, November 4, 12
11. 现象分析
⻚页面生命周期⻓长、迭代频繁的情况最容易产生代码冗余
未用到 用到 扫描⻚页面数 Last-Modified
weibo frame.css 1686 485 25 11/02
index.css 299 38 25 10/10
A_index.css 3203 384 25 11/02
douban _init_.css 163 180 47 10/10
_all.css 256 118 47 10/17
douban.css 2011 360 47 11/01
Sunday, November 4, 12
12. douban.css douban.js
150
112.5
75
37.5
0
2007-7 2009-2 2010-7 2011-7 2012-6
Sunday, November 4, 12
20. A/B测试、灰度上线、快速迭代、响应式 发......
杂度更高、迭代更快、多版本并存......传统架构难于应付
深度重构前端架构,增强前端的“机动性”
Sunday, November 4, 12
21. A/B测试、灰度上线、快速迭代、响应式 发......
杂度更高、迭代更快、多版本并存......传统架构难于应付
深度重构前端架构,增强前端的“机动性”
a. 改造模板系统,实现真正模块化的view层
b. 完善静态文件管理系统
Sunday, November 4, 12
22. 模块
在程序设计中,为完成某一功能所需的一段程序或子程序;
或指能由编译程序、装配程序等处理的独立程序单位;
或指大型软件系统的一部分。
Sunday, November 4, 12
23. 模块
在程序设计中,为完成某一功能所需的一段程序或子程序;
或指能由编译程序、装配程序等处理的独立程序单位;
或指大型软件系统的一部分。
1. 模块如何 分
2. 模块应具有的独立性。装载/卸载不影响整个系统运行
Sunday, November 4, 12
27. 传统写法
<head>
<script src="jQuery.js"></script>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="boutique.css">
<style>
#db-boutique { ... }
</style>
</head>
<body>
<%include file=”boutique.html” />
<script src="boutique.js"></script>
<script>
$('#bn').click(function(e){ ... });
</script>
</body>
Sunday, November 4, 12
28. 传统写法
<head>
<script src="jQuery.js"></script>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="boutique.css">
<style>
#db-boutique { ... }
</style>
</head>
<body>
<%include file=”boutique.html” />
<script src="boutique.js"></script>
<script>
$('#bn').click(function(e){ ... });
</script>
</body>
<!-- 模块文件boutique.html -->
<div id=”db-boutique” class="mod">
<a id="bn">link</a>
</div>
Sunday, November 4, 12
29. 传统写法
<head>
<script src="jQuery.js"></script>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="boutique.css">
<style>
#db-boutique { ... }
</style>
</head>
<body>
<%include file=”boutique.html” />
<script src="boutique.js"></script>
<script> 没有真正独立
$('#bn').click(function(e){ ... });
带来维护隐患
</script>
</body>
<!-- 模块文件boutique.html -->
<div id=”db-boutique” class="mod">
<a id="bn">link</a>
</div>
Sunday, November 4, 12
30. 传统写法 模块真正实现独立
<head>
<script src="jQuery.js"></script> <head>
<link rel="stylesheet" href="common.css"> <script>
<link rel="stylesheet" href="boutique.css"> ${istatic(‘/js/lib/head.js’)|n}
<style> </script>
#db-boutique { ... } <link rel="stylesheet" href="common.css">
</style> </head>
</head>
<body>
<body>
<%include file=”boutique.html” />
<%include file=”boutique.html” />
<script src="do.js" data-corelib="jQuery.js"></scri
<script src="boutique.js"></script> </body>
<script> 没有真正独立
$('#bn').click(function(e){ ... });
带来维护隐患
</script>
</body>
<!-- 模块文件boutique.html -->
<div id=”db-boutique” class="mod">
<a id="bn">link</a>
</div>
Sunday, November 4, 12
31. 传统写法 模块真正实现独立
<head>
<script src="jQuery.js"></script> <head>
<link rel="stylesheet" href="common.css"> <script>
<link rel="stylesheet" href="boutique.css"> ${istatic(‘/js/lib/head.js’)|n}
<style> </script>
#db-boutique { ... } <link rel="stylesheet" href="common.css">
</style> </head>
</head>
<body>
<body>
<%include file=”boutique.html” />
<%include file=”boutique.html” />
<script src="do.js" data-corelib="jQuery.js"></scri
<script src="boutique.js"></script> </body>
<script> 没有真正独立
$('#bn').click(function(e){ ... });
带来维护隐患
</script>
</body> <!-- 模块文件boutique.html -->
<%block filter=”collect_css”>
#db-boutique { ... }
<!-- 模块文件boutique.html -->
</%block>
<div id=”db-boutique” class="mod"> <div id=”db-boutique” class="mod">
<a id="bn">link</a> <a id="bn">link</a>
</div> </div>
<script>
Do(‘boutique.js’, function(){
$('#bn').click(function(e){ ... });
});
</script>
Sunday, November 4, 12
36. 业务代码和通用代码分离
公共文件冗余小
模块迭代,模块内部解决
Sunday, November 4, 12
37. 业务代码和通用代码分离
公共文件冗余小
模块迭代,模块内部解决
安装和卸载方便
Sunday, November 4, 12
38. 业务代码和通用代码分离
公共文件冗余小
模块迭代,模块内部解决
安装和卸载方便
封装 杂度和多 状态
Sunday, November 4, 12
39. n年前
发
3年前 前端按需加载&依赖管理
静态文件构建
现在
Sunday, November 4, 12
40. n年前
发
3年前 前端按需加载&依赖管理
静态文件构建
现在
Sunday, November 4, 12
43. <a href="url" class="btn"><i>+</i>添加照片</a>
<a href="url" class="btn" style="padding-left:8px;" >
<i style="margin-right:2px; font-size:14px;" >+</i>添加照片
</a>
<%block filter="collect_css">
.btn-add-pic { padding-left:8px; }
.btn-add-pic i { margin-right:2px;font-size:14px; }
</%block>
<a href="url" class="btn btn-add-pic"><i>+</i>添加照片</a>
Sunday, November 4, 12
45. 线上态
发态
Sunday, November 4, 12
48. 内联 用
少量⻚页面业务相
Sunday, November 4, 12
50. 项目JS文件 使用场景
外联 用 (粗粒度)
内联 用 (细粒度)
Sunday, November 4, 12
51. <link rel="stylesheet" type="text/css" href="http://l.yimg.com/zz/combo?nn/lib/metro/g/
core_yui_3.4.2.css&nn/lib/metro/g/core_srvc_1.0.9.css&nn/lib/metro/g/core_mod_1.0.116.css&nn/
lib/metro/g/fp/fp_widecc_0.0.23.css&nn/lib/metro/g/fp/fp_403_0.0.2.css&nn/lib/metro/g/
masthead/masthead_0.2.141.css&nn/lib/metro/g/masthead/masthead_403_0.0.34.css&nn/lib/metro2/g/
announcebar/announcebar_1.0.22.css&nn/lib/metro/g/contentcarousel/
contentcarousel_widecc_0.0.12.css&nn/lib/metro/g/multimedia/multimedia_1.0.48.css&nn/lib/
metro/g/contentcarousel/contentcarousel_news_0.0.10.css&nn/lib/metro/g/mostpopular/
mostpopular_0.0.10.css&nn/lib/metro/g/marketindices/marketindices_widecc_0.0.9.css&nn/lib/
metro/g/news/offlead_0.1.15.css&nn/lib/metro/g/news/news_accordion_0.1.83.css&nn/lib/metro/g/
contentcarousel/contentcarousel_polls_0.0.37.css&nn/lib/metro/g/tuc/tuc_wave3_0.0.20.css&nn/
lib/metro/g/tabbar/tabbar_0.0.45.css&nn/lib/metro/g/uicontrib/locdrop_widget_0.0.6.css&nn/lib/
metro/g/mail/mail_0.0.44.css&nn/lib/metro/g/mail/mail_403_0.0.21.css&nn/lib/metro/g/fptoday/
fptoday_widecc_0.0.20.css&nn/lib/metro/g/pa/pa_widecc_0.1.25.css&nn/lib/metro/g/pa/
pa_detached_0.1.91.css&nn/lib/metro/g/pa/pa_add_0.1.68.css&nn/lib/metro/g/tts/
tts_widecc_0.0.18.css&nn/lib/metro/g/footer/footer_0.1.79.css&nn/lib/metro/g/footer/
subfooter_0.0.15.css" />
Sunday, November 4, 12
52. <link rel="stylesheet" type="text/css" href="http://l.yimg.com/zz/combo?nn/lib/metro/g/
core_yui_3.4.2.css&nn/lib/metro/g/core_srvc_1.0.9.css&nn/lib/metro/g/core_mod_1.0.116.css&nn/
lib/metro/g/fp/fp_widecc_0.0.23.css&nn/lib/metro/g/fp/fp_403_0.0.2.css&nn/lib/metro/g/
masthead/masthead_0.2.141.css&nn/lib/metro/g/masthead/masthead_403_0.0.34.css&nn/lib/metro2/g/
announcebar/announcebar_1.0.22.css&nn/lib/metro/g/contentcarousel/
contentcarousel_widecc_0.0.12.css&nn/lib/metro/g/multimedia/multimedia_1.0.48.css&nn/lib/
metro/g/contentcarousel/contentcarousel_news_0.0.10.css&nn/lib/metro/g/mostpopular/
mostpopular_0.0.10.css&nn/lib/metro/g/marketindices/marketindices_widecc_0.0.9.css&nn/lib/
metro/g/news/offlead_0.1.15.css&nn/lib/metro/g/news/news_accordion_0.1.83.css&nn/lib/metro/g/
contentcarousel/contentcarousel_polls_0.0.37.css&nn/lib/metro/g/tuc/tuc_wave3_0.0.20.css&nn/
lib/metro/g/tabbar/tabbar_0.0.45.css&nn/lib/metro/g/uicontrib/locdrop_widget_0.0.6.css&nn/lib/
metro/g/mail/mail_0.0.44.css&nn/lib/metro/g/mail/mail_403_0.0.21.css&nn/lib/metro/g/fptoday/
fptoday_widecc_0.0.20.css&nn/lib/metro/g/pa/pa_widecc_0.1.25.css&nn/lib/metro/g/pa/
pa_detached_0.1.91.css&nn/lib/metro/g/pa/pa_add_0.1.68.css&nn/lib/metro/g/tts/
tts_widecc_0.0.18.css&nn/lib/metro/g/footer/footer_0.1.79.css&nn/lib/metro/g/footer/
subfooter_0.0.15.css" />
Sunday, November 4, 12
53. CSS模块库
<link rel="stylesheet" type="text/css" href="http://l.yimg.com/zz/combo?nn/lib/metro/g/
core_yui_3.4.2.css&nn/lib/metro/g/core_srvc_1.0.9.css&nn/lib/metro/g/core_mod_1.0.116.css&nn/
lib/metro/g/fp/fp_widecc_0.0.23.css&nn/lib/metro/g/fp/fp_403_0.0.2.css&nn/lib/metro/g/
masthead/masthead_0.2.141.css&nn/lib/metro/g/masthead/masthead_403_0.0.34.css&nn/lib/metro2/g/
announcebar/announcebar_1.0.22.css&nn/lib/metro/g/contentcarousel/
contentcarousel_widecc_0.0.12.css&nn/lib/metro/g/multimedia/multimedia_1.0.48.css&nn/lib/
metro/g/contentcarousel/contentcarousel_news_0.0.10.css&nn/lib/metro/g/mostpopular/
mostpopular_0.0.10.css&nn/lib/metro/g/marketindices/marketindices_widecc_0.0.9.css&nn/lib/
metro/g/news/offlead_0.1.15.css&nn/lib/metro/g/news/news_accordion_0.1.83.css&nn/lib/metro/g/
contentcarousel/contentcarousel_polls_0.0.37.css&nn/lib/metro/g/tuc/tuc_wave3_0.0.20.css&nn/
lib/metro/g/tabbar/tabbar_0.0.45.css&nn/lib/metro/g/uicontrib/locdrop_widget_0.0.6.css&nn/lib/
metro/g/mail/mail_0.0.44.css&nn/lib/metro/g/mail/mail_403_0.0.21.css&nn/lib/metro/g/fptoday/
导入依赖的CSS模块
fptoday_widecc_0.0.20.css&nn/lib/metro/g/pa/pa_widecc_0.1.25.css&nn/lib/metro/g/pa/
pa_detached_0.1.91.css&nn/lib/metro/g/pa/pa_add_0.1.68.css&nn/lib/metro/g/tts/
tts_widecc_0.0.18.css&nn/lib/metro/g/footer/footer_0.1.79.css&nn/lib/metro/g/footer/
subfooter_0.0.15.css" />
Sunday, November 4, 12
54. 静态文件管理
• 前端的加载器负责粗粒度文件的按需加载和依赖管理
• 后端的静态文件管理
a. 细粒度文件引用
b. 自动分离内联css/js代码
c. css/js的预处理(SCSS、伪语法)
Sunday, November 4, 12
55. 变量 嵌套
mixin
单行注释
运算
Sunday, November 4, 12
56. 变量 嵌套
mixin
单行 vs. 多行 ?
单行注释
问题:输入优美输出 运算
肿 :(
嵌套问题:避免 杂的嵌套
组合问题:冗余的定义
继承问题:继承多余的定义
保持简单!保持 平!
调试问题,chrome24支持SASS的Source Mapping
Sunday, November 4, 12
57. “ 用”不是简单的组合
完全 用。大而全未必好
粒度越细、功能越单一越有可能 用
基础代码 用
copy 用
Sunday, November 4, 12
60. 小粒度
元件
框架
http://sheldonbrown.com/retroraleighs/catalogs/1977-drawings/pages/22-track-bike.html
Sunday, November 4, 12
61. 小粒度
元件
框架 大粒度
组件
http://sheldonbrown.com/retroraleighs/catalogs/1977-drawings/pages/22-track-bike.html
Sunday, November 4, 12
62. 小粒度
元件
框架 大粒度
组件
组件的分解
http://sheldonbrown.com/retroraleighs/catalogs/1977-drawings/pages/22-track-bike.html
Sunday, November 4, 12
63. .. ...
超越传统响应式 发
Sunday, November 4, 12
64. 响应性图片
响应性布局
viewport meta
原始⻚页面
Sunday, November 4, 12
65. 适配大小、精度
响应性图片 dataURL
320 px mobile portrait
响应性布局 480 px mobile landscape
600 px small tablet
768 px tablet portrait
viewport meta 1024 px tablet landscape
1280 px desktop
原始⻚页面
Sunday, November 4, 12
66. 性能优化 注⻚页面性能、电池消耗
响应交互 增强触屏行为和兼容 面事件
适配大小、精度
响应性图片 dataURL
320 px mobile portrait
响应性布局 480 px mobile landscape
600 px small tablet
768 px tablet portrait
viewport meta 1024 px tablet landscape
1280 px desktop
前端 原始⻚页面
响应性模块 可定制、可组合
后端
响应性静态资源文件(JS/CSS) 可兼容 面版,也可以重新 发
Sunday, November 4, 12
68. <%def name=”main”>
<%include file=”path/mod1.html” args=”data=data” />
<%include file=”path/mod2.html” args=”data=data” />
<%include file=”path/mod3.html” args=”data=data” />
</%def>
<%def name=”mobile_main”>
${self.main()} ## 简单!
</%def>
path/mod3.html
mobile_mod3.html
js_path/mod3.js
mobile_mod3.js Desktop Mobile
css_path/mod3.css
mobile_mod3.css
Sunday, November 4, 12
69. 增强触屏行为和兼容 面事件
mobile浏览器和 面浏览器的事件模型有明显差
Sunday, November 4, 12
70. 增强触屏行为和兼容 面事件
mobile浏览器和 面浏览器的事件模型有明显差
Sunday, November 4, 12
71. 增强触屏行为和兼容 面事件
mobile浏览器和 面浏览器的事件模型有明显差
a. 绑定document上的事件代理挂了
b. mouse事件的顺序:
mouseover > mousemove > mousedown > mouseup
c. mouseout再次击非点击区域时触发
d. click最后发生(大约300ms,有延迟感), 且有可能不发生
Sunday, November 4, 12
72. 增强触屏行为和兼容 面事件
mobile浏览器和 面浏览器的事件模型有明显差
a. 绑定document上的事件代理挂了
body { cursor:pointer; }
b. mouse事件的顺序:
mouseover > mousemove > mousedown > mouseup
c. mouseout再次击非点击区域时触发
d. click最后发生(大约300ms,有延迟感), 且有可能不发生
利用jQuery的sepcial event重写click、mousedown/up/move
https://gist.github.com/3358036
TouchPunch(http://touchpunch.furf.com)
Sunday, November 4, 12
73. 调试和监测
http://hikejun.com/blog/?p=693
Sunday, November 4, 12
75. 发环境同时预览 ;P
group.douban.com
Sunday, November 4, 12
77. tcpdump
sudo tcpdump -i en1 -n -s 0 -w yourapp.pcap tcp or port 53
用Charles或pcapperf打
Sunday, November 4, 12
78. 用户不 心流量
快、流畅、省电
Sunday, November 4, 12
80. 新“角色” − 电池
iPhone 5: 3.8v 5.45Whr, 5.45 / 3.8 = 1434mAh
总电能 5.45 * 3600 = 19620J(焦耳)
iPhone 4S: 3.7v 5.3Whr, 5.3 / 3.7 = 1432mAh
总电能5.3 * 3600 = 19080J(焦耳)
HTC(G6,我的手机): 3.7v , 1500mAh
总电能3.7 * 1.5 * 3600 = 19980J(焦耳)
S3: 3.8v 7.98Whr, 7.98/3.8 = 2100mAh
总电能7.98 * 3600 = 28728J(焦耳)
Sunday, November 4, 12
81. 下载260K,耗电约25J
上传260K,耗电约15J
显示600px宽的图片(no cache),耗电约1.4J
显示600px宽的图片(cache),耗电约0.6J
显示JPEG图片耗电 < PNG < GIF
有cache能耗远小于没cache
......
出自 http://www2012.wwwconference.org/proceedings/proceedings/p41.pdf
Sunday, November 4, 12
82. 平均⻚页面大小
下载260K,耗电约25J 1M
上传260K,耗电约15J
显示600px宽的图片(no cache),耗电约1.4J
显示600px宽的图片(cache),耗电约0.6J
显示JPEG图片耗电 < PNG < GIF
有cache能耗远小于没cache
......
出自 http://www2012.wwwconference.org/proceedings/proceedings/p41.pdf
Sunday, November 4, 12
83. 影响能耗的 键因子:
cache、请求数、图片大小、js/css的冗余、css/js的 杂度
Sunday, November 4, 12
84. 总结
1. 改造模板系统和完善静态文件管理系统提升机动性,在此基础上进行重构
2. 模块化view层的实现
3. 在上面实现后,顺利进入响应式 发阶段
4. 响应式 发实践的一些收获
Sunday, November 4, 12
85. Q &A
kejun
hikejun.com | twitter/weibo: @kejunz | douban.com/people/listenpro
Sunday, November 4, 12
86. 我 说完了
看?
芳, 你怎么
元
Q &A
kejun
hikejun.com | twitter/weibo: @kejunz | douban.com/people/listenpro
Sunday, November 4, 12
87. 谢谢!
kejun
hikejun.com | twitter/weibo: @kejunz | douban.com/people/listenpro
Sunday, November 4, 12