内容简介:关于公司老项目的视图渲染解决方案
最近公司的一个老旧的项目因为业务各方面原因突然活跃起来了,每日大概uv 100
,pv能达到 3500
。虽然不知道为什么 uv
和 pv
相差能那么大,但是由于使用多了,老项目的一些弊端就出来,需要不停地添加功能和修复BUG,所以我成了这个项目的前端接盘侠。
这项目技术栈大概是 jQuery
+ backbone
,项目重构按照目前的情况来看短期是不可能了,所以要做的就是如何去优化。
问题
这个项目大概有差不多一年的历史了,在js文件里你随处可以看见下面这种代码,将函数挂载到全局变量上,然后又在另一个js文件里调用。
# one.js window.example = funtion () { console.log('test'); } # two.js example()
刚开始的时候的时候一脸懵比,后来已经习惯了,如果你在当前文件里没有找到该函数的声明,别急,随着 html
里面 js
的引用顺序挨个往前面翻就是了,总能找到。
下面才是今天真正的问题,我在某个文件里面看到了大量类似于这样的代码(样式class省略,内容进行了处理)
var msg = '<div>' + '<div>时间是{{time}} 名字是{{username}</div>' + '<div>内容是{{content}}</div>' + '</div>';
当数据产生变化的时候,都会出现类似下面的代码,由此产生了大量冗余代码。
var html = msg.replace(/\{\{time\}\}/, time); html = html.replace(/\{\{username\}\}/, time); html = html.replace(/\{\{content\}\}/, time); $('#target').html(html);
同时 jquery
的 html
插入的实际上是清空了 #target
里的 DOM
,然后再插入重新生成新的 DOM
,当然这样会有很大的性能损耗,其次每次这样操作都会产生大量重复的冗余代码。如果代码仅仅只有这么几行或者十几行或许不会有多大影响,但是我扫了一下整个项目,这样的代码粗略估计有至少200行以上了,后续开发中不可避免还会遇到类似的问题,所以写一个小插件解决这问题。
问题解决
为了解决上述的问题,我写了一个小插件 Shaco
,名字来源于LOL中的恶魔小丑萨科的英文名字,寓意为 神出鬼没
地解决视图渲染的问题。 Shaco
的总代码量目前102行,其原理是通过数据劫持来监听(Observer)数据的变化,通过编译(Compile)来解析指定元素节点下的变量(Mustach语法),当数据产生变化时通知调用update的updateText刷新文本。
关于Shaco
Shaco
主要由三部分组成
Shaco
需要提供的参数为需要解析的元素, 其值建议使用 id
唯一标志。然后就是需要 Shaco
需要劫持的数据 data
,务必为 Object
。使用例子:
var shaco = new Shaco({ el: '#app', data: { a: 1 } });
插件效果:
代码解析部分仅提供部分代码,详情请查看 项目Github地址 的 lib/shaco.js
Shaco
关于Shaco函数部分, $el
为元素节点, $data
为需要劫持的数据, $save
用来存储模板解析含有变量的节点对象。
function Shaco (options) { this.$el = document.querySelector(options.el); // 元素节点 this.$data = options.data; // 需要劫持的数据 this.$save = []; // 模板解析 {node, value, text} // 数据劫持 observe(this.$data, this); // 模板解析 this.$compile = new Compile(this.$el, this); }
Observer
Observer
模块中通过 defineProperty
去设置 set
监听数据,当数据发生变化时, observe
新的数据,同时通知 update
刷新视图。
set: function (newVal) { if (newVal === val) { return; } var oldData = JSON.parse(JSON.stringify(vm.$data)); val = newVal; observe(newVal, vm); updater.updateText(vm, oldData); }
Compile
Compile
模块中对节点进行解析,当节点是文本节点(即没有子节点)时进行 compileText
, compileText
在处理是会把命中的节点压入 $save
中。
compile: function (node, vm) { var that = this; var childNodes = node.childNodes; [].slice.call(childNodes).forEach(function(node){ if (that.isElement(node)) { that.compile(node, vm); return; } else if (that.isText(node)) { that.compileText(node, vm) } }); }
updater
updater
在被劫持的数据更新时会被触发,此时会扫描数据,对 $save
中节点进行遍历,然后更新数据。
性能问题
在进行视图渲染更新的时候,可以看到 Shaco
只更新了对应DOM的 nodeValue
而jQuery html()在进行视图渲染更新的时候,重新渲染了整个对应的DOM
对比一下两个操作耗费的时间,发现jQuery html()的大部分时间都集中在 Rendering
和 Paitning
上,而 Shaco
因为只刷新来的 nodeValue
所以没在这上面耗费多少时间。
题外话
Shaco
采用 ES5
的语法编写,对于使用 jquery
维护的老项目可以毫无顾忌的使用,不用担心任何问题。关于为什么不加入指令解析、watcher等?如果有这需要的话为什么不直接使用 vue
呢?说到底 Shaco
只是为一些老项目提供视图渲染方面的一个解决办法,减少冗余代码,而并非说是要徒手撸一个 MVVM
框架出来。
关于 input
使用 Shaco
, 你可以这样做。
<div id="app2"> <p>显示:{{value}}</p> 输入:<input type="text" oninput="input(this)"> </div> var shaco2 = new Shaco({ el: '#app2', data: { value: '' } }); function input (e) { shaco2.$data.value = e.value; }
嗯,后来问了下项目当初是 实习生
负责的,所以维护也理所当然落到了我头上!
╮( ̄▽ ̄”)╭”),估计当初也没想到这项目后来居然活了吧~
贴一张图~
老夫子写代码就用jquery,复制粘贴就是干.jpg
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 关于公司老项目的视图渲染解决方案
- ajax – 将视图渲染为字符串,然后在cakephp中输出json
- iOS小技巧·把子视图控制器的视图添加到父视图控制器
- CouchDB 视图简介及增量更新视图的方法
- c# – 将数据从部分视图传递到其父视图
- Django 基于函数的视图与基于类的视图
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Python
Paul Barry / O'Reilly Media / 2010-11-30 / USD 49.99
Are you keen to add Python to your programming skills? Learn quickly and have some fun at the same time with Head First Python. This book takes you beyond typical how-to manuals with engaging images, ......一起来看看 《Head First Python》 这本书的介绍吧!