avalon之所以能在页面处理1W个绑定(angular对应的数字是2000),出于两个重要设计——基于事件驱动的双向绑定链及智能CG回收机制。

avalon的双向绑定链是通过Object.definePropertiesVBScript,将要操作VM属性变成一种访问器属性。访问器属性是一种特殊的属性,需要我们为它指定setter、getter方法(当然,这也是框架内部生成的,只有计算属性可以做一些干预),当用户对此属性进行赋值操作时,就会调用setter方法,对它进行读取时,就会进行getter方法。我们通过hack进这两个方法,做各种各样的事,如依赖收集及事件广播、触发$watch回调,其中最重要一点,就是将关联在它上面的订阅数组的对象逐个触发,从而更新视图,这也是双向绑定链的原理。比如说

vm.me = 111

<div ms-text="me"></div>

me就会有一个订阅数组,里面放着一个对象,里面包含如此操作这个div的信息,如果有两个绑定属性的值存在me这个变量,这数组就有两个对象。触发是用户修改vm.me 时立即发生,不需要像angular那样调用$apply或$digest方法,也不像angular那样将所有绑定对象都检测一次。angular之所以会卡死,因为页面一旦绑定对象多,这检测时间也恐怖了,并且这检测可能是深遍历对象的属性进行比较的。而avalon每次只会检测其一个属性上对应的小数组,因此检测压力会相对少许多。

由于绑定属性会转换绑对象,并且绑定对象包含要操作的元素节点或文本特点这种惯例的存在,就会引发第二个问题,如果回收这些绑定对象呢?angular虽然为$scope对象添加了一个$destroy,但没有针对绑定对象有更精细的操作。avalon在1.36之前在notifySubscribers进行绑定对象的element进行是否在DOM树的检测,不在就将绑定对象的所有属性都置为null,并从当前订阅数组移除。

avalon1.36/1.4引入全新的CG回收机制,页面上的{{}}插值表达式ms-*属性,经过扫描后,变成一个个绑定对象,对象包含name、value、type、param、vmodels、priority、args、vmodels、evaluator、handler等属性与方法,有些绑定对象还会多出template、 group、$repeat、proxies等属性(1.36前更多,现在都大幅精简了),因此绑定对象也算一个比较大的JS对象,页面上的绑定属性越多,这些绑定对象自然也越多,占用着大用的内存。如果页面发生一些移除节点操作,涉及这些绑定属性原来所在的元素节点,那么这些绑定对象也应该销毁,我们就必须将binding.element 置为null,才会方便CG回收。之前是位于notifySubscribers方法里进行,但它处理的目标是一个很小的数组,不会检测所有绑定对象,因此总有漏网之鱼,这样积沙成塔,在移动端上就是一个很大的问题,会弄崩手机浏览器。

在1.36/1.4中,内部定义一个全局的$$subscribers数组,所有生成的绑定对象都放到里面,然后每当我让VM的属性发生变化时,就一定会经过notifySubscribers方法,这时对$$subscribers数组的对象进行检测。并且这检测也有技巧,为了减少检测频率对浏览器造成压力,每次检测至少经过333ms才会进行一次。

检测手段,是判定binding.element是否位于DOM树上,由于element可能是元素节点,文本节点或注释节点,IE的原生contains方法也有BUG,于是检测也是多种多样的。

var $$subscribers = []
function removeSubscribers() {
for (var i = $$subscribers.length, obj; obj = $$subscribers[--i]; ) {
var data = obj.data
var el = data.element
var remove = el === null ? 1 : (el.nodeType === 1 ? typeof el.sourceIndex === "number" ?
el.sourceIndex === 0 : !root.contains(el) : !avalon.contains(root, el))
if (remove) { //如果它没有在DOM树
$$subscribers.splice(i, 1)
avalon.Array.remove(obj.list, data)
// log("debug: remove " + data.type)
obj.data = obj.list = data.evaluator = data.element = data.vmodels = null
}
}
}
var beginTime = new Date(), removeID
function notifySubscribers(accessor) { //通知依赖于这个访问器的订阅者更新自身
var currentTime = new Date()
clearTimeout(removeID)
if (currentTime - beginTime > 333) {
removeSubscribers()
beginTime = currentTime
} else {
removeID = setTimeout(removeSubscribers, 333)
}
var list = accessor[subscribers]
if (list && list.length) {
var args = aslice.call(arguments, 1)
for (var i = list.length, fn; fn = list[--i]; ) {
var el = fn.element
if (typeof fn === "function") {
fn.apply(0, args) //强制重新计算自身
} else if (fn.$repeat) {
fn.handler.apply(fn, args) //处理监控数组的方法
} else if (fn.element) {
var fun = fn.evaluator || noop
fn.handler(fun.apply(0, fn.args || []), el, fn)
}
}
}
}

当然这是两个要点,为了提高性能,avalon也像一些大型应用程序那样,善于利用缓存机制。之前是使用FIFO缓存算法,1.4后改为LRU。

<!DOCTYPE html>
<html>
<head>
<title>监控函数</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="avalon.js"></script>
<style> .odd{
background: green;
}
</style>
<script type="text/javascript">
var model = avalon.define({
$id: "test",
array: [1, 2, 3, 4, 5],
more: 10,
isOdd: function(el) {
return (el + model.more) % 2 === 1
},
add: function() {
model.array.push(1)
},
remove: function() {
model.array.pop()
},
change: function(){
model.more = 11
} }) </script>
</head>
<body ms-controller="test" >
<ul>
<li ms-repeat="array" ms-class="odd:isOdd(el)">{{el}}</li>
</ul>
<p><button ms-click="add">add</button><button ms-click="remove">remove</button><button ms-click="change">change</button></p>
</body>
</html>

迷你MVVM框架 avalonjs 学习教程22、avalon性能大揭密的更多相关文章

  1. 迷你MVVM框架 avalonjs 学习教程19、avalon历史回顾

    avalon最早发布于2012.09.15,当时还只是mass Framework的一个模块,当时为了解决视图与JS代码的分耦,参考knockout开发出来. 它的依赖收集机制,视图扫描,绑定的命名d ...

  2. 迷你MVVM框架 avalonjs 学习教程1、引入avalon

    avalon是国内最强大的MVVM框架,没有之一,虽然淘宝KISSY团队也搞了两个MVVM框架,但都无疾而终.其他的MVVM框架都没几个.也只有外国人与像我这样闲的架构师才有时间钻研这东西.我很早之前 ...

  3. 迷你MVVM框架 avalonjs 学习教程18、一步步做一个todoMVC

    大凡出名的MVC,MVVM框架都有todo例子,我们也搞一下看看avalon是否这么便宜. 我们先从react的todo例子中扒一下HTML与CSS用用. <!doctype html> ...

  4. 迷你MVVM框架 avalonjs 学习教程16、过滤器

    avalon的过滤器是参考自angular与rivets.它也被称做管道文本过滤器,它的处理对象只能是文本(字符串),它只能用在文本绑定中,并且只能是双花括号形式.下面是各大家的过滤器比较: rive ...

  5. 迷你MVVM框架 avalonjs 学习教程3、绑定属性与扫描机制

    在MVVM框架中,你都会看到页面定了许多奇怪的属性,比如knockout的data-☆,angular的ng-☆,avalon的ms-☆,此外还有一些只写文本节点上的双花括号,它们统称为指令.ms-☆ ...

  6. 迷你MVVM框架 avalonjs 学习教程17、avalon的一些配置项

    本章节,主要是介绍avalon.config方法,通过它来制定一些更贴心的功能. 一般情况下,我们在使用ms-controller绑定时,需要添加一个ms-controller类名,目的是为了防止网速 ...

  7. 迷你MVVM框架 avalonjs 学习教程20、路由系统

    SPA的成功离开不这三个东西,分层架构,路由系统,储存系统.分层架构是我们组织复杂代码的关键,这里特指MVVM的avalon:路由系统是将多个页面压缩在一个页面的关键:储存系统特指本地储存,是安全保存 ...

  8. 迷你MVVM框架 avalonjs 学习教程11、循环操作

    avalon是通过ms-repeat实现对一组数据的批量输出.这一组数据可以是一个数组,也可以是一个哈希(或叫对象).我们先从数组说起吧. 第二节就说,凡是定义在VM中的数组,如果没有以$开头或者没放 ...

  9. 迷你MVVM框架 avalonjs 学习教程4、数据填充

    MVVM是前端的究极解决方案,你们可能用过jQuery,但那个写的代码不易维护:你们可以听过说requirejs与seajs,传说中的模块开发,加载器,但它们的最终目标是打包:你们可能听过unders ...

随机推荐

  1. ORACLE基本操作备忘

    通过CMD登录SQLPLUS 的语句 C:\Users\Administrator>sqlplus /nolog SQL> conn sys/pwd as sysdba; 导入导出数据库( ...

  2. POJ1639顶点度限制最小生成树

    题目:http://poj.org/problem?id=1639 见汪汀的<最小生成树问题的拓展>. 大体是先忽略与根节点相连的边,做一遍kruscal,得到几个连通块和一个根节点: 然 ...

  3. python 典型文件结构

    #/usr/bin/env/ python #(1) 起始行 "this is a test module" #(2) 模块文档(文档字符串) import sys import ...

  4. bzoj1212 L语言

    Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D ...

  5. css属性所对应js属性

    document.getElementById("xx").style.xxx中的所有属性是什么,css对应js: 盒子标签和属性对照 CSS语法(不区分大小写) JavaScri ...

  6. Linux-Zabbix

    ###############################安装######################################## 安装部分我写了文档,可能不是很完善 文档如下→→ [ ...

  7. js 下关于json的销毁和添加

    var json={a:1,b:2} 现在给json添加个c,可以这样写 json.c=3或json["c"]=3 我删除一个属性 delete json.a alert(json ...

  8. 第5章 进程环境(1)_进程结构(task_struct)

    1. 进程的概念和进程结构 1.1 进程 (1)程序(program):是一些保存在磁盘上有序指令的集合,是存放在磁盘文件中的可执行文件.但没有任何执行的概念,它是静态的. (2)进程(process ...

  9. python_基础算法

    本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序.希望大家回顾知识的时候也能从我的这篇文章得到帮助. 概述 十种常见排序算法可以分为两 ...

  10. Nature | 光学CNN层替换传统CNN层,超省电

    CNN 计算效率的研究一直备受关注,但由于功率和带宽的严格限制,CNN 仍难以应用在嵌入式系统如移动视觉.自动驾驶中.在斯坦福大学发表在 Nature 旗下 Scientific Reports 的这 ...