关于公司老项目的视图渲染解决方案

栏目: jQuery · 发布时间: 6年前

内容简介:关于公司老项目的视图渲染解决方案

最近公司的一个老旧的项目因为业务各方面原因突然活跃起来了,每日大概uv 100 ,pv能达到 3500 。虽然不知道为什么 uvpv 相差能那么大,但是由于使用多了,老项目的一些弊端就出来,需要不停地添加功能和修复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);

同时 jqueryhtml 插入的实际上是清空了 #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 模块中对节点进行解析,当节点是文本节点(即没有子节点)时进行 compileTextcompileText 在处理是会把命中的节点压入 $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()的大部分时间都集中在 RenderingPaitning 上,而 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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

用户体验草图设计

用户体验草图设计

比尔·巴克斯顿(Bill Buxton) / 黄峰 / 电子工业出版社 / 2009-11 / 168.00元

《用户体验草图设计:正确地设计,设计得正确(全彩)》:比尔·盖茨亲笔推荐版 人因国际、百度、华为、微软、腾讯用户体验部门联合推荐!一起来看看 《用户体验草图设计》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具