仔细观察一下这里的函数,你会看到该组件在第一次调用渲染时,将使用 createElement 创建两个子节点,并设置它们的属性并且缓存。第二次或者第一万次调用时,children-array将被缓存,不会发生任何调用。
// 在第一次调用时候 $.$不存在 $.$会等于 后面的数组
// 第二次调用 $.$ 是存在的,无运行时消耗
$.$ = $.$ || 数组
其中查看源码,我们可以看到 setChildren 函数都是对真实DOM 进行了操作。获取之前的DOM节点进行一系列操作后将当前节点返回并缓存。
tag.prototype.setChildren = function (new$,typ){ var old = this._tree_; if (new$ === old && (!(new$) || new$.taglen == undefined)) { return this; }; if (!old && typ != 3) { this.removeAllChildren(); appendNested(this,new$); } else if (typ == 1) { var caret = null; for (var i = 0, items = iter$(new$), len = items.length; i < len; i++) { caret = reconcileNested(this,items[i],old[i],caret); }; } else if (typ == 2) { return this; } else if (typ == 3) { var ntyp = typeof new$; if (ntyp != 'object') { return this.setText(new$); }; if (new$ && new$._dom) { this.removeAllChildren(); this.appendChild(new$); } else if (new$ instanceof Array) { if (new$._type == 5 && old && old._type == 5) { reconcileLoop(this,new$,old,null); } else if (old instanceof Array) { reconcileNested(this,new$,old,null); } else { this.removeAllChildren(); appendNested(this,new$); }; } else { return this.setText(new$); }; } else if (typ == 4) { reconcileIndexedArray(this,new$,old,null); } else if (typ == 5) { reconcileLoop(this,new$,old,null); } else if ((new$ instanceof Array) && (old instanceof Array)) { reconcileNested(this,new$,old,null); } else { // what if text? this.removeAllChildren(); appendNested(this,new$); }; this._tree_ = new$; return this; };
如果我们使用了动态属性。代码如下
tag Component def render <self> <h1.title> "Welcome" # 有 50% 几率 拥有 red class <p.desc .red=(Math.random > 0.5)> "IMBA"
可以得到如下代码,详细查看可以看出,imba 提取了可变量,放入了 synced 函数中,每次渲染中只会执行 synced 里面的数据,所以依然会得到极高的渲染速度
var Component = Imba.defineTag('Component', function(tag){ tag.prototype.render = function (){ var $ = this.$; return this.setChildren($.$ = $.$ || [ _1('h1',$,0,this).flag('title').setText("Welcome"), _1('p',$,1,this).flag('desc').setText("Roulette") ],2).synced(( $[1].flagIf('red',Math.random() > 0.5) ,true)); }; });
精确的抽取不可变量,然后无需虚拟DOM 计算,同时对于真实DOM 还进行了缓存,我们可以看出 memoized DOM 与 虚拟DOM 不同,memoized DOM 是具有实际的性能收益。
imba 框架“虚假”的性能测试
我们在上面看到了 imba 框架的理论基础,那么他是否真的比vue快50倍?当然不是,这也就是在上面说我是标题党的原因。
浏览器的运行机制
浏览器本身只能达到 60 fps( 1 秒刷新了60次 )。当然了,其实对于体验而言,60fps的体验已经差不多够用了,也就是浏览器渲染上大概需要 17ms 去渲染一次。事实上无论是每秒操作dom 5w次还是 1000次,浏览器渲染引擎也只会记录当前的脏数据。然后在需要渲染时候再进行重绘与重排。
真实世界的内存限制
面对 memoized DOM 的缓存优化以及更少 GC 带来的运行时提升,我们需要更多内存来对每一个 dom节点进行缓存。这个在初始化渲染时有大量的消耗。同时我们的浏览器执行速度和渲染速度已经足够快了,虚拟DOM已经完全够用了。
imba 框架与浏览器的畅想
Google io 大会 chorme Portals 技术
单页应用程序(Single Page Applications,SPA)提供了很好的页面交互,但代价是构建的复杂性更高,多页面应用程序(Multi-page Applications,MPA)更容易构建,但最终会在页面之间出现空白屏幕。
Portals 结合了这两者的优势,主要用于改进网页交互体验,目标是无缝导航。它类似于 iframe ,内嵌在网页上,但可以导航到页面内容上。用户在一个页面跳转另一个内容时,虽然 URL 相应地发生变化,但是不需要打开另一个窗口,此时该内容标记的 Portals 会变成原来页面的顶级页面,同时原来页面在其后保持主进程地位。现场演示了这对于购物体验的极大便利,此外还有对漫画这类单页面应用的演示。
js引擎 与 渲染引擎的关联