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

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

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

最近公司的一个老旧的项目因为业务各方面原因突然活跃起来了,每日大概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


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

查看所有标签

猜你喜欢:

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

Dive Into Python 3

Dive Into Python 3

Mark Pilgrim / Apress / 2009-11-6 / USD 44.99

Mark Pilgrim's Dive Into Python 3 is a hands-on guide to Python 3 (the latest version of the Python language) and its differences from Python 2. As in the original book, Dive Into Python, each chapter......一起来看看 《Dive Into Python 3》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换