博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
迷你MVVM框架 avalonjs v0.5.1发布,性能大幅提高
阅读量:7144 次
发布时间:2019-06-29

本文共 6243 字,大约阅读时间需要 20 分钟。

早在avalon在IE与firefox有较为严重的性能问题,chrome等则由于它们太逆天因此看不出。主要原因是动态插入节点时,each由于一些帮方法考虑不周,结果不得不逐个插入,虽然使用了nextTick进行缓冲,但延迟明显。然后avalonjs v5把大体的架构完成了,然后重点改良这些方法了。在v5.1中所有延迟都没有了,即便在IE6下也很接近之前在chrome的运行效果。算是一次非常出色的改进。

1, addItemView方法不再逐个复制,逐个插入了。

//原来 function addItemView(index, item, data) {        var scopes = data.scopeList;        var collection = data.collection;        var parent = data.element;        var doc = parent.ownerDocument;        var textNodes = [];        var scope = createItemModel(index, item, collection, data.args);        scopes = [scope].concat(scopes)        for (var node = data.view.firstChild; node; node = node.nextSibling) {            var clone = node.cloneNode(true);            if (collection.insertBefore) { //必须插入DOM树,否则下为注释节点添加自定义属性会失败                parent.insertBefore(clone, collection.insertBefore);            } else {                parent.appendChild(clone);            }            if (clone.nodeType === 1) {                scanTag(clone, scopes.concat(), doc); //扫描元素节点            } else if (clone.nodeType === 3) {                textNodes.push(clone); //插值表达式所在的文本节点会被移除,创建循环中断(node.nextSibling===null)            } else if (clone.nodeType === 8) {                clone.nodeValue = node.nodeValue + "" + index;                if (!clone.addScope) {                    clone.$scope = scope;                    clone.addScope = "addItemView";                }                clone.$view = data.view.cloneNode(false);            }        }        avalon.nextTick(function() {            for (var i = 0; node = textNodes[i++]; ) {                scanText(node, scopes.concat(), doc); //扫描文本节点            }        })    }

改为

function addItemView(index, item, data) {        var scopes = data.scopes;        var list = data.list;        var parent = data.element;        var doc = parent.ownerDocument;        var scope = createItemModel(index, item, list, data.args);        scopes = [scope].concat(scopes);        var view = data.view.cloneNode(true);//★★★★        var textNodes = [];        var elements = [];        for (var node = view.firstChild; node; node = node.nextSibling) {            if (node.nodeType === 1) {                elements.push(node);            } else if (node.nodeType === 3) {                textNodes.push(node);            } else if (node.nodeType === 8) {                node.id = node.nodeValue + index; //设置路标                node.$scope = scope;                node.$view = view.cloneNode(false);//★★★★            }        }        // parent.insertBefore(el, null) === parent.appendChild(el)        parent.insertBefore(view, list.place || null);        for (var i = 0; node = elements[i++];) {            scanTag(node, scopes.concat(), doc); //扫描文本节点        }        avalon.nextTick(function() {            if (!parent.inprocess) {                parent.inprocess = 1; //作用类似于display:none                var hidden = parent.hidden; //http://html5accessibility.com/                parent.hidden = true;//★★★★ 防止reflow            }            for (var i = 0; node = textNodes[i++];) {                scanText(node, scopes.concat(), doc); //扫描文本节点            }            if (parent.inprocess) {                parent.hidden = hidden;                parent.inprocess = 0;            }        })    }

2,新的路标系统:avalon使用一个注释节点来确认每个子模板的起点, 像emberjs则是使用两个script节点, knockout是使用两个注释节点 。

//原来//路标是指每个模板最开头的那个注释节点    //
// 假若 index == 2, 返回
function findIndex(elem, listName, index) { for (var node = elem.firstChild; node; node = node.nextSibling) { if (node.nodeType === 8 && (node.nodeValue === listName + index)) { return node; } } } //重置所有路标 function resetIndex(elem, name) { var index = 0; for (var node = elem.firstChild; node; node = node.nextSibling) { if (node.nodeType === 8) { if (node.nodeValue.indexOf(name) === 0) { if (node.nodeValue !== name + index) { node.nodeValue = name + index; var scope = node.$scope || {}; scope.$index = index; } index++; } } } }

现在的逻辑简化成这样:

function findIndex(elem, index) { //寻找路标        for (var node = elem.firstChild; node; node = node.nextSibling) {            if (node.id === node.nodeValue + index) {//★★★★                return node;            }        }    }    function resetIndex(elem, name) { //重置路标        var index = 0;        for (var node = elem.firstChild; node; node = node.nextSibling) {            if (node.nodeType === 8 && node.nodeValue === name) {//★★★★                if (node.id !== name + index) {                    node.id = name + index;//★★★★                    node.$scope.$index = index;                }                index++;            }        }    }

3,移除模板的两个函数合并成一个,因此整体代码量都下降了。

//原来    function removeItemView(node, listName) {        var nodes = [node];        var view = node.$view;        for (var check = node.nextSibling; check; check = check.nextSibling) {            //遇到下个路标时就断开            if (check.nodeType === 8 && check.nodeValue.indexOf(listName) === 0) {                break            }            nodes.push(check);        }        for (var i = 0; node = nodes[i++]; ) {            view.appendChild(node);        }        return [view, check]; //返回被移除的文档碎片及下一个路标    }    //移除each中的多个子视图,返回它们对应的文档碎片集合    function removeItemViews(node, listName, number) {        var views = [];        do {            var array = removeItemView(node, listName);            if (array[1]) {                views.push(array[0]);                node = array[1];            } else {                break            }        } while (views.length !== number);        return views;    }

现在是

function emptyNode(parent) {//它直接用于clear与update方法        while (parent.firstChild) {            parent.removeChild(parent.firstChild);        }    }    function removeItemView(node, id) {         var nodes = [node];        var view = node.$view;        for (var check = node.nextSibling; check; check = check.nextSibling) {            if (check.nodeType === 8 && check.id === id) {                break            }            nodes.push(check);        }        for (var i = 0; node = nodes[i++];) {            view.appendChild(node);        }        emptyNode(view);//★★★★        view = null;//★★★★    }

可以到查看效果!如果有什么好的改进,记得pull request啊!

转载地址:http://sggrl.baihongyu.com/

你可能感兴趣的文章
PHP响应式VIP电影影视系统源码 带自动采集和会员管理系统
查看>>
iframe里弹出的层显示在整个网页上
查看>>
开源项目Bug悬赏任务
查看>>
ubuntu 和 win10 双系统安装 及 pyopengl 环境配置修改
查看>>
学习计划书
查看>>
为什么你的智能手表功能这么多,ICMAX来解答
查看>>
tor_api
查看>>
给国外电子邮箱发海外邮件用什么邮箱好?
查看>>
Connectify+Wireshark捕获手机APP的数据包
查看>>
CentOS 6.5 生产环境编译安装LNMP
查看>>
8.6 “数据库设置”服务器选项
查看>>
两种方法反转单链表
查看>>
二叉树递归前序、中序、后序遍历
查看>>
在VIEW中加载UICollectionView
查看>>
散列桶
查看>>
eclipse修改 服务器默认路径
查看>>
[iOS Animation]-CALayer 视觉效果
查看>>
8 步搭建 Node.js + MongoDB 项目的自动化持续集成
查看>>
windowsserver 2012 R2 创建群集失败
查看>>
iostat和iowait详细解说--查看磁盘瓶颈
查看>>