js面向数据编程(DOP)一点分享

这篇文章发布于 2011年01月18日,星期二,21:59,归类于 JS实例。 阅读 88115 次, 今日 2 次 21 条评论

 

一、小历史

面对数据编程(data-oriented-programme)这个概念第一次接受是在去年前年阿里巴巴举行的D2前端论坛上,来自Baidu金大为:《模板语言与大前端》的分享,其视频链接如下:

去年,哦,已经2011年了,应该是前年了,那会儿正是我闭关修炼之时,尚未开始工作,js呢就是个菜,而且还是个非常瘦弱的豆芽菜,所以当时概念的接受比较囫囵。但是自知是有用的东西,管他懂不懂,先塞到大脑库存中缓存,以便日后读取。

后有幸参与js方面的工作,后又非常幸运的参与了大数据量js交互的工作。后发现,采用传统的DOM操作(添加、删除等)逻辑过多,牵扯甚广,容易出疏漏和bug,维护也颇为不便,更为关键的是性能问题,例如在IE6下速度明显低很多。如何改进?在男足版混乱的思考后,想到了在数据层进行修改删除等,然后DOM唯一相关的操作就是批量刷新与事件绑定。后发现逻辑清晰了,性能提升了,维护与修改也相当轻松。开始尝试时还是有些手生的,不过这半年来多次折腾,现在对其使用思路愈发清晰,趁最近项目进入测试阶段,可以歇口气,拿出来简单说说。

二、先扯点远的

我们先跳出代码,从更直观与易于理解的宏远世界去看为什么面向数据的编程为何在大数据量的编程中更轻松,简单与便于维护。

拿修房子举例。假设朱大长由于某些不便透露的原因,要对房子进行一些整修,然后他找了几个给力的工人:一是建房能手,天天,其擅长做添砖加瓦的活;第二位是来自拆迁队的姗姗,其擅长“剃掉”那些长得不规矩的砖瓦;第三位是装修达人,边边,其擅长对毛坯的砖瓦做美化,能是房子变得更漂亮。我们可以想象出来,当这几个人参与了修理房屋的工作,状况应该是这样的(见下图):
DOM操作与建房子示意图 张鑫旭-鑫空间-鑫生活

天天觉得,这里应该加一块砖头,于是,他就在房子的这个位置加了块砖头;姗姗同学嫌某些砖头长得很碍眼,决定把它去掉,于是她就亲自爬到房子上把这块砖头利索抹掉了;边边也不甘寂寞,很积极勤奋地给砖墙粉刷。这几个人工作都是亲自,且直接在房子上做操作。ok,目前的状况看来,一切都是理所当然,应该这样做。我们平时修房子不就是这样的吗?几个工人在房子上,拆拆补补,装饰装饰。

确实,就像这修厕所,一两个人敲敲打打也就这么搞定了;就算是是修平房或是我们乡下的那种两层楼,也可以搞定,请几个大工(拆除,新建)和些小工(和泥粉饰),在房子上折腾个把星期就可以了。在中国,大部分的建筑都是这种小打小闹的,所以,这种在屋子上临时拆建的方式似乎成了理所当然。

但是,世界之大,有些方法与法则在某些地方时行不通的。比如说现在有栋80年代的12层的酒店要重修修整,单纯的请一些人拆拆补补就搞不定了,倒不是人数不够的问题,古代有句话就做“牵一发而动全身”,像10层以上的大型建筑,而且是老建筑,结构不明,建筑牢固度大大下降。你推到2楼左边的一面墙,说不定3楼的卫生间就塌掉了,各建筑,各层级,附带外部居民,道路等,都是有关联的,就算是再有经验的建筑工人,也会有疏忽与遗漏的地方,说不定就会弄场上海胶州路大火。

所以,很多时候,大型建筑不是旁击侧敲,小打小闹的整修,而是直接爆破重来。这其实跟我们做页面交互感觉类似。

三、修整房子与页面交互

我们在页面上编辑,删除或是添加元素其实就是修房子的过程。大多数情况下,我们的房子是很简单的。所以,要删哪个东西直接remove就可以了,直接对准目标,啪——干掉!如下例子:
有针对性的删除某个节点 张鑫旭-鑫空间-鑫生活

但是,有时候,如果页面元素数据量很大,交互很频繁。指哪儿打哪儿的方法就开始有些吃不消了。举个很常见的例子,autocomplete,如在纯洁的百度上搜索”geli”,此时就会有autocomplete下拉,按下↓键,结果就会看到首条目“格里芬”被选中了。
百度搜索格里芬 张鑫旭-鑫空间-鑫生活

这里就是属于大数据量交互的地方,输入框按键有效果,鼠标上下键移动有效果,列表hover也有效果等。那上图的上下键移动选中条目,条目的样式修换显示是DOM上的removeClass/addClass的操作吗?哦哦哦,no,no,no!这里每一次的按键,每一次的鼠标hover都是整个HTML的刷新,而不是很小家子器得去寻找目标节点然后去修改其样式。在现代浏览器下,使用这种指定DOM修改的方法是看不出什么性能上的不足的,但是在IE6浏览器下,你就要做好便秘和延迟的准备了。

JavaScript慢的不是字符串处理,数据遍历,而是DOM相关操作。所以,要是什么地方可能会有频繁的DOM操作,啊哦,要注意了,看看你是在休整乡下的二层楼房还是在着手高层建筑的修缮工作?

如果是高层建筑,我建议你,不要再原建筑上修修补补了,直接爆破重来。

反映到JavaScript上就是操作(添加,删除,编辑)等不在DOM上进行,而是在数据上进行(常见的JSON,或是普通的对象字面量,数组都是可以的),DOM唯一相关的工作就是负责全部HTML的一次性刷新。

如果还是天天,姗姗,边边为例做个示意图的话,应该如下:
面向数据编程与建房子示意图 张鑫旭-鑫空间-鑫生活

一般而言,这种HTML的刷新速度肉眼是看不出什么间隔来的,即使重绘和渲染都很out的IE6浏览器也是如此。于是,我们的工作就很简单了,什么addChild, removeChild这些属性直接可以说goodbye了,翻译成日语就是“赛有拉拉”。把终数据准备好,套上HTML模板,innerHTML属性,就搞定了。哇,多么简单,多么明了,这种感觉就像是你连续12个小时盯着凤姐,然后一回头,突然看见志林姐就在你身后对你甜甜的微笑。

千言万语还不如一束玫瑰来得实在,看实例说话吧。

四、面向数据编程实例之北京蔬菜价格

demo
您可以狠狠地点击:面向数据编程实例demo

demo页面截图缩略图如下,全屏自适应的:
面向数据编程demo截图缩略图 张鑫旭-鑫空间-鑫生活

点击列表处的按钮,可以看到选项进入了可编辑状态,您可以通过点击按钮或是直接操作单行文本框改变数值;当数值为0的时候,又会回到默认的选择按钮状态。
点击购买按钮后进入数值可编辑状态 张鑫旭-鑫空间-鑫生活

这里的一系列操作,例如普通按钮变成文本框,点击加(+)减(-)按钮后数值的改变都不是直接在当前DOM上的操作,而是实时的HTML列表刷新。怎样,就算是万恶的IE6浏览器也基本上感觉不到晃动啊或是延时这类不好的体验。现在,我们打开潘多拉的盒子来一看究竟。

打开盒子前首先要明确:操作→数据→HTML模板→刷新这条线。

操作嘛,没什么好说的,就是点击啊,input change啊等,对于数据,其格式如下:

var dataVegetables = {
    typeId: "bbbbbb",
    goods: {
        "000010": { name: "白萝卜 ", price: 0.4, units: "/斤", num: 0 },
        "000011": { name: "菠菜", price: 0.8, units: "/斤", num: 0 },
        "000012": { name: "菜花", price: 1.3, units: "/斤", num: 0 },
        "000013": { name: "长茄子", price: 0.2, units: "/斤", num: 0 },
        "000014": { name: "慈菇", price: 3.5, units: "/斤", num: 0 },
        "000015": { name: "葱头 ", price: 0.85, units: "/斤", num: 0 },
        "000016": { name: "大白菜 ", price: 0.43, units: "/斤", num: 0 },
        "000017": { name: "大葱 ", price: 0.75, units: "/斤", num: 0 },
        "000018": { name: "冬瓜", price: 0.5, units: "/斤", num: 0 },
        "000019": { name: "冬笋  ", price: 10.0, units: "/斤", num: 0 }
    }
};

现在,我们做的任何操作,都只与这个数据有关。例如,我们要把白萝卜的数量改成2,直接

dataVegetables.goods["000010"].num = 2;

而不是去修改input的value为2。

HTML模板其实就是用来组装这些数据的HTML片段,如下截图:
HTML模板片段 张鑫旭-鑫空间-鑫生活

而最后一步非常简单,就是将用模板组装的HTML刷新
在本文demo中就是下图所高亮的这一行:
innerHTML的刷新 张鑫旭-鑫空间-鑫生活

从上到下,整个线路都非常简单清晰。由于HTML页面的最终显示都来自且唯一来自一个数据源,所以,只要把数据源处理好了,就不要担心哪里会出什么纰漏,这要比人人都可以在页面上大补丁要安全高效的多,我想这应该很好理解。

不是什么高深的东西,我想,说这些应该足够了。

五、久违的结语

最近在忙着架构js与CSS的东西,好久没更新了。也就是一晃球的功夫,只怪时间跑得太快。

在处理大数据量交互,尤其是这种带有repeat性质的js交互的时候,面向数据的编程毋庸置疑要比在DOM上处理简单高效的多的多。要注意这里的使用情况——大数据量交互,平时修修茅房这类小打小闹其实还是直接DOM操作来得更快捷些,你说修个茅房还塞两个炸掉重来就实在有点艺术派了。面向数据的编程还有点小小不足可能在于SEO,毕竟,把内容数据化,HTML字符串化对于搜索引擎可能有些不礼貌。

本文更多的是帮助自己知识梳理、技能提高的些小结,水平有限,要是文章有什么表述不准确的地方欢迎指正,也欢迎各种方式的交流。

得,就这多,最后附上个让人凌乱的笑话:

QB:本人在美国上学,前两天,走在路上,突然看见一个很嘻哈的黑哥们戴着耳机摇头晃脑的朝我走来。 一边走还一边念念有词。 当他走近一些后从耳机里渐渐飘出:“ 当初是你要分开,分开就分开。。。” 我当时就零乱了。。。

(本篇完)

分享到:


发表评论(目前21 条评论)

  1. zerov说道:

    前端玩得这么溜的,为何不自创一个前端框架来?或者优化现有的著名框架,如easyui/jquery/vue等?

    • sti说道:

      是页面重构走出来的css大佬,不是webapp工程化出现的大佬,你说bootstrap还差不多,

  2. jinphen说道:

    这种把房子拆了重来的方式不适合图片,因为每当写时,浏览器会去加载图片,这之中有一定的时间差。

    • 叶落萧萧说道:

      我没记错的话,如果浏览器之前有请求到的图片,一般都是会放置在页面缓存中的,所以应该不会对速度有影响的

  3. awen说道:

    适合模块化js编程。

  4. czonechan说道:

    同意7楼的看法,IE6下闪得发亮。

  5. gt说道:

    晚了,回复,谢了

  6. gt说道:

    你好, 张鑫,我想学CSS3,我在网站找不到类似的书,请问有什么介绍.

  7. asins说道:

    还有一点,像这种大数据交互的东西在绑事件时最好使用事件委托,这样可以避免每次刷新时重绑事件

  8. asins说道:

    很给力的深入啊,去年我在做一项目时选择使用简单的模板引擎来简化数据的拼装,但没你这么深入,受益不少啊,

    这是我以前写的简化数据拼装的,nootn.com/blog/Develop/26/

  9. movever说道:

    不错 豁然开朗 确实看到志林姐姐了

  10. wind说道:

    阅! 觉得不错,有些地方觉得还是写的不错的,比如用json交互,的确性能有很大提升,但是如果面临大量的html拼装,就很让人崩溃了,因为我们之前的一个项目就这样,我们是j2ee,用的freemarker做的显示层,基本的小的html数据量就json,大数据量就ajax直接load集合文件,比如table。再一点,我不太赞同用太多的js实现页面表示层。一是js终归是弱语言,二是如果js文件内容超过几百行接手的人会出现恶心的生理反应! 欢迎砸砖:gfz@w.cn

  11. workgang说道:

    博主 我认为 您这个情况 更像是 一栋大楼 其中一户人家需要装修。 结果你吧整栋大楼给重建了。以达到装修一户人家的效果。

    你举得这个例子。应该可以更小的颗粒化, 以一户人家为单位。而不是一栋大楼为单位。

    呵呵。我的愚见,不要见怪。

  12. zhengxi说道:

    很好的文章喜欢~~~

  13. 水色说道:

    面向对象只是一种开发模式,又怎么会和seo有什么关系呢?
    只不过目前搜索引擎对后端输出的页面识别的比较好,
    而对前端输出的页面不怎么识别而已罢了。

    你的demo做的不错,但是这篇文章显然说的文不对题,貌似再说的是用js生成页面,
    和面向对象半毛钱关系都没有吧。

  14. 静水之人说道:

    哈哈,原来我在用ajax时也是先写好html模板,然后把更新的数据附加到模板上。不过没有lz总结的这么细致。

  15. wordgold说道:

    很不错的想法,启发很大!

  16. duke说道:

    很给力的分享,用重绘替代dom操作

  17. birdstudio说道:

    很给力的文章!谢谢分享!