前端组件编写经验————图片回去再传

Web应用已从单纯的HTMLRIA发展,用户在追求功能基础的同时,也更加青睐于快捷、绚丽和多功能效果的展现。目前基于前端UI组件的封装与开发是众多互联网公司的一种常见选择。然而与传统web页面相比,突然出现大量带有生命周期的javascript领域对象,无疑会减缓浏览器的执行效率与增加对应的内存消耗。在这里,我将带着在开发与重构大集中前端组件中所遇到的一系列问题,与大家一起分享在降低大量javascript代码对性能的影响及内存的消耗方面所做的努力。

查看内存消耗与测试执行效率工具

a) 利用Firefoxfirebug工具查看js下载量与加载时间

 

b) 利用windows 任务管理器,通过多次刷新进行内存泄漏的检查

 

c) 编写测试js执行效率计算方法

 

    还有比如测内存泄漏的sIEve,Javascript Leaks Detector等,而我常用上面三种方式对复杂js进行测试与调整。

根据大集中前端开发中所面临的问题,我们所采取的一系列方式

    (1) Mootools强大的面象对象思想,但目前版本1.3其事件功能在内存泄漏方面给我们带来了巨大挑战,每增加一条$('id').addEvent('type',funName)语句都会产生相应内存的泄漏,试想每个ui组件里面都已经绑定了大量的事件(交互的需要),而在大集中开发中有接近四十多个可显示的ui组件,而每个页面上存放的组件一般不应低于十个,与传统web页面相比,浏览器执行的时间与内存的消耗上都会大大加重。如何解决这些问题呢?

    A、尽量让每个组件的事件注册到最外层标签上,根据relatedTargettarget.id等相关属性进行分发处理。

Button组件中统一注册与分发处理:

 

 

 

    B、采用原生态事件注册$('id').οnclick=fn;

    Tabpanel组件事例:

 

 

    方式A中尽管在最外层DIV中注册事件,但结合mootools还是会产生内存的泄漏,而B方案中采用A与原生事件的结合,从而有效避免内存的泄漏。但同时留下一个缺点即只能在一类事件中注册一个方法。

    (2)良好的后台数据结构与前端html结构给js带来的福祉?某些组件要与后台交互如combosauditnoteportal等后台传入的数据结构,决定了html结构的组装。

后台结构:工作流组件auditNote当要展示多个审批意见时,其数据结构

[{workflowId:"runMode",actId:"41B4C55D75134D0FBDE876294F837FB7",nodeId:"000006",nodeName:"运方专责审批",

noteRecord:[{actorName:"陈明",createTime:"2010-05-04 11:15",updateTime:"2010-05-04 16:25",note:"运方专责审批意见A"}]},

{workflowId:"runMode",actId:"41B4C55D75134D0FBDE876294F837FB9",nodeId:"000007",nodeName:"调度专责审批",

noteRecord:[{actorName:"李盈",createTime:"2010-05-05 11:15",updateTime:"2010-05-05 16:25",note:"调度专责审批A"}]},

{workflowId:"runMode",actId:"41B4C55D75134D0FBDE876294F837FB8",nodeId:"000008",nodeName:"汇总部门A",

noteRecord:[{actorName:"超级管理员",createTime:"2010-05-06 11:15",updateTime:"2010-05-12 16:25",note:"汇总部门A意见"}]}

]

   在上面的数据结构中并不知道当前审批节点位置,所以在前端需要额外开销去查询当前节点位置

 

查询当前审批节点位置

    同时,当查询一条记录在流程中不存在轨迹时,后台数据结构中仍然给我们返回我们要查询的不存在的节点信息,故我们又不得不用js去控制。

 

蓝色标记部分判断组件是否需要隐藏

    倘若能在后台将上面数据结构中数组中加上当前节点信息,以及解决查询错误问题对于复杂UI组件来讲其开发,执行与维护将起到关键性作用。

    HTML结构:精简的html结构不仅能减轻浏览器渲染的压力而且能降低js编码的复杂度,还能降低维护成本。

    以tabpanel组件为例,其tab页的实现是采用多个ul标签实现

 

    点击tab页时,样式上的变化,js代码为:

 

 

   简化后:

 

    代码:

 

    简单明了的HMTL结构,逻辑清晰信息丰富的后台数据结构,为复杂UI的设计减压。

    (3)为什么我们要同时修改一个元素多个属性,为什么我们会先隐藏元素再显示元素?

    先认识下重排与重绘的概念:当浏览器下载完所有组件的jscssimg,浏览器中会形成两种数据结构即dom树(页面结构)与渲染树(dom节点如何显示),dom树在渲染树中至少存在一个对应的节点(隐藏的dom元素在渲染树中没有对应的节点)

    那么什么情况下浏览器会去重绘页面呢:当元素的几何属性(大小 位置,内容)改变时都会发生重排——当窗口大小改变时,全局重排,特别有滚动条出现。当改变元素的背景色时,只会发生重绘(不需要重排),因为元素的布局并没有改变。重绘与重排会给web应用程序的组件带来反应迟钝。

UI组件中改变一个元素的位置与大小是一种司空见惯了的事件,那么我们所做的操作只能是最小化重绘与最小化重排。

A、一次性改变多个样式

    Portal.js的例子:

 

B、使元素脱离文档(隐藏元素方式,使用文档片段方式,拷贝(clone)元素)

    Tree.js的例子:

 

    重排一定会重绘,最小化重绘与重排是我们遵循的基本准则。

    当我们要构建一个元素内容,其内容量很大时,我们为什么采用数组与innerHTML?

    这种情况下通常会用forwhile等循环来组装html结构。我们不希望重复性的选择与修改元素内容,因为这样会导致重绘与重排的次数增加,所以用数组作为容器存储动态的html结构。旧版浏览器(IE6)中采用innerHTML比用原生dom方法document.createElement()mootools$('id').set('html',content)都要快上3.6倍以上。所以我们选择了innerHTML方式。

    Poral组件:

 

    如何做到带有图标的文本框,自适应窗口时,保证图片与文本框结构不走样,是否要采用js动态去计算?

 

最大化

    变形

 

缩小

    对于自适应,百分比无疑是一种常用并且方便的方式。当图片大小固定,外面容器按百分比缩放后,里面input输入框按相应百分比缩放后,组件会变形。或者用javascript通过复杂计算得到一个比较适合的百分比。其实你如果对css应用很了解,只需将图标float设为right即可。

 

最大化窗口

 

缩放后的窗口

    代码:

 

    同样对于树的导航,滚动条的问题,多出的滚动条,我们当然可以通过js去计算,但比较简单的方式同样是修改css

 

    当js文件过大,我们可能最终发布js时求于打包压缩的方式(合并一个js)让浏览器一次加载,对于大型应用中,这是我们发布时必须经历的一个步骤,但是在之前我们可能还要做更细腻的操作。

A、将一个组件中用户常用功能代码放在一个js文件中,其它不常用功能以继承或实现方式来形成另一js

如菜单右键菜单继承普通菜单:

 

左键菜单

 

右键菜单继承左键菜单

B、采用单例模式,如消息框、日历组件、选人选部门,在框架初始化时,实例化一个全局对象构造出基础标签结构与相关参数,以后调用时,只需传入相关特性参数来构建相关界面。对于什么样的组件适合采用单例模式,个人觉得是在不同界面中点击同一超链接(图标或按扭等)后弹出UI界面的组件。

    如:Messagebox组件

 

供全局调用方法

 

如果实例化后,就从容器中取出

接下的一些总结不再全部分析原因与贴出源码,希望读者用心体会

1) 闭包中尽量创建新的内部变量去指向外部变量

2) 对象的生成尽量采用{}[ ] 等直接量,而非 new object()new array()

3) 尽量用位操作 如对奇数与偶数的判断 (1&i )

4) 大量if else时采用switch代替

5) 避免操作html集合,如$$("")因为浏览器会时刻去计算该集合所包含的内容

6) 缓存常用的元素以及可将一会变量存在标签上

7) 采用克隆而非新建节点

8) 尽量不采用try{}catch(e){}setTimeOut()with(){}s语句,因为它会改变作用域链

9) 从数据结构中选择元素而非在DOM树上去选择元素

10) 避免用太多iframe以及在拖动中让iframe显示 

11) 减少点号层次的访问深度,可以事先定义相关变量,取其部分。

12) 尽量不要采用形如for(){el.innerHTML+=""+text+"}

13) 在程序中不要让变量之间形成网络上的引用,即变量不可达,特别是在事件与闭包中容易出     现内存泄漏。

总结:思想来源于积累,优雅来自于沉淀,我们已经在路上。





你可能感兴趣的:(web,前端)