那么 memoized DOM 又是怎么做的呢?把 DOM 节点的控制直接放入内存之中。类似于此类优化.
function getEls(sel) {
// 设置缓存
if (!getEls.cache) getEls.cache = {}; // 如果缓存中存在 el,直接返回
if (getEls.cache[sel]) {
return getEls.cache[sel];
}
// 没有去通过 DOM 查询
const r = document.querySelectorAll(sel || '☺'),
length = r.length;
// 缓存并返回元素节点
return getEls.cache[sel] = (length == 1) ? r[0] : r;
}
我们可以测试一下。这里我写一个 getElsByDocument 以及 simplePerTest。
// 直接通过 querySelectorAll 获取节点
function getElsByDocument(sel) {
const r = document.querySelectorAll(sel || '☺'),
length = r.length;
return length == 1 ? r[0] : r;
}// 简单性能测试
function simplePerTest(fn, el) {
const fnName = fn.name
console.time(fnName)
// 2000 次操作
for(let i = 0,len = 2000; i < len; i++) {
fn(el)
}
console.timeEnd(fnName)
}

这个缓存的节点查询可要比 querySelectorAll 快了 140倍以上啊,随着 img 节点越多,得到的性能提升也越高啊。如果imba 框架中所有的节点都在内存中呢?同时,我们还会得到一个 js 运行时优化( GC 的大量减少),因为虚拟DOM 要维护一个树,在进行多次 crud 之后就会产生大量无用对象从而导致浏览器进行 GC,而 memoized DOM 在多次 crud 不会进行多次 GC。(可能会在渲染引擎中 GC?但我感觉渲染引擎中GC 要比JS 中影响要小很多。挖个坑,研究完渲染引擎再来探讨一下)
框架实践
实例如下所示:
tag Component
def render
<self>
<h1.title> "Welcome"
<p.desc> "I am a component"上面的自定义组件会编译成下面的js
var Component = Imba.defineTag('Component', function(tag){
tag.prototype.render = function (){
var $ = this.$;
// 返回dom
return this.setChildren($.$ = $.$ || [
createElement('h1',$,0,this).flag('title').setText("Welcome"),
createElement('p',$,1,this).flag('desc').setText("I am a component")
]).synced();
};
});仔细观察一下这里的函数,你会看到该组件在第一次调用渲染时,将使用 createElement 创建两个子节点,并设置它们的属性并且缓存。第二次或者第一万次调用时,children-array将被缓存,不会发生任何调用。










