avalon与双缓冲技术

avalon1.5一个重要技术升级是引进异步渲染。异步渲染在游戏界有一个更专业的名字,叫双缓冲。游戏界要刷新界面与咱们刷新浏览器视图,面临的问题是一致的。视图是由许多存在套嵌关系的方块组成,它们每个的改动,均可能引发reflow(其父节点,其父父节点的大小从新计算),这是形成性能问题的关键。javascript

双缓冲技术的主要原理是:当一个动画争先显示时,程序又在改变它,前面的画面还没显示完,程序又要求从新绘制,这样屏幕就会不停闪烁。为了不闪烁,可使用双缓冲技术,将要处理的图片都放在内存中处理好事后,再将其显示到屏幕上。这样出来的就是完整的图像,不会出现闪烁现象。html

MVVM框架带来一个革命性的优化是,用户只操做VM就好了,视图由框架来同步更新。所以这个同步过程,咱们就能够加入优化。好比说angular,就是靠用户手动调用$apply来驱动脏检测,只有数据不一致的地方,才会操做DOM。因而没有了aaa.innerHTML = "xxx&"; aaa.innerHTML = "xxx"的愚蠢代码。java

可能用户会说我怎么可能会这样写呢,那是你由于用于jquery,看到它是在同一个循环中对某个节点执行屡次相同的操做。node

再回过头来看avalon。avalon是基于事件驱动(经过Object.defineProperty劫持了对象的属性),当用户修改了某属性,就会当即同步视图。这种机制最大的好处是,方便与jQuery或其余操做DOM的库配合使用jquery

          
    avalon.config.async = false
            var vm = avalon.define({
                $id: "test",
                a: 1
            })
           setTimeout(function(){
               vm.a = 2
               alert(document.getElementById("aaa").innerHTML) //2
           }, 1000)
      
       
 
 
 
 
{{a}}
// 2

坏处是可能会形成性能问题。做为测试,咱们在avalon的text指令加入这样一行日志: git

          
avalon.directive("text", {
    update: function (value) {
        console.log(value)
        var elem = this.element
        value = value == null ? "" : value //不在页面上显示undefined null
        if (elem.nodeType === 3) { //绑定在文本节点上
            try { //IE对游离于DOM树外的节点赋值会报错
                elem.data = value
            } catch (e) {
            }
        } else { //绑定在特性节点上
            if ("textContent" in elem) {
                elem.textContent = value
            } else {
                elem.innerText = value
            }
        }
    }
})

` 测试页面为:github

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="avalon.js"></script>
        <script>
            avalon.config.async = false
            var vm = avalon.define({
                $id: "test",
                a: 1
            })
            setTimeout(function () {
                vm.a = 2
                vm.a = 3
                vm.a = 4
                vm.a = 5
                vm.a = 6
            })
        </script>
    </head>
    <body>
        <div ms-controller="test">
            <div id="aaa">{{a}}</div>
        </div>
    </body>
</html>

image

在avalon1.5中,打开 avalon.config.async = true开关后,就只输出两次。第一次扫描确定当即出来,之后就是异步了。数组

image

avalon作到这个很是简单,由于通过屡次重构优化,从VM到V的同步,都要通过notifySubscribers这个方法。它是用来执行当前属性对应的订阅数组中的每一个对象的update方法。浏览器

function notifySubscribers(subs) {
    if (!subs)
        return
    if (new Date() - beginTime > 444 && typeof subs[0] === "object") {
        rejectDisposeQueue()  //若是这个绑定对象的节点已经被移出DOM树,那么须要对这sub对象进行GC回收处理
    }
    for (var i = 0, sub; sub = subs[i++]; ) {
            sub.update && sub.update() //最小化刷新DOM树
     }
}

` 如今改为这样了app

function notifySubscribers(subs) {
    if (!subs)
        return
    if (new Date() - beginTime > 444 && typeof subs[0] === "object") {
        rejectDisposeQueue()//...
    }
    if (kernel.async) {
        buffer.render()
        for (var i = 0, sub; sub = subs[i++]; ) {
            if (sub.update) {
                avalon.Array.ensure(buffer.queue,sub)//这里有去重处理
            }
        }
    } else {
        for (var i = 0, sub; sub = subs[i++]; ) {
            sub.update && sub.update()//最小化刷新DOM树
        }
    }
}

buffer对象很简单

var buffer = {
    render: function () {
        if (!this.locked) {
            this.locked = 1
            avalon.nextTick(function () {
                buffer.flush()
            })
        } 
    },
    queue: [],
    flush: function () {
        for (var i = 0, sub; sub = this.queue[i++]; ) {
            sub.update()
        }
        this.queue.length = this.locked = 0
    }
}

这是历次重构,精简入口带来的好处。换言之,作同样的东西,只有一个函数负责。那么要对功能作扩展,就直接对 此函数进行处理就好了。

只要减小了视图无效的刷新,那么avalon的性能就会当即上去,这对大表格的渲染刷新能立竿见影!

avalon的官网地址: avalonjs.github.io 有关双缓冲的实现能够这里:avalon2.buffer

相关文章
相关标签/搜索