avalon v5.1发布,性能大幅提高

2024-05-13 21:38

本文主要是介绍avalon v5.1发布,性能大幅提高,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

早在avalon在IE与firefox有较为严重的性能问题,chrome等则由于它们太逆天因此看不出。主要原因是动态插入节点时,each由于一些帮方法考虑不周,结果不得不逐个插入,虽然使用了nextTick进行缓冲,但延迟明显。然后avalon 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是使用两个 。


//原来
//路标是指每个模板最开头的那个注释节点
    //<!--xxx1--><tag><tag><text><!--xxx2--><tag><tag><text><!--xxx3--><tag><tag><text>
    // 假若 index == 2, 返回<!--xxx2-->
 
    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啊!

这篇关于avalon v5.1发布,性能大幅提高的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/986901

相关文章

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

微信公众号脚本-获取热搜自动新建草稿并发布文章

《微信公众号脚本-获取热搜自动新建草稿并发布文章》本来想写一个自动化发布微信公众号的小绿书的脚本,但是微信公众号官网没有小绿书的接口,那就写一个获取热搜微信普通文章的脚本吧,:本文主要介绍微信公众... 目录介绍思路前期准备环境要求获取接口token获取热搜获取热搜数据下载热搜图片给图片加上标题文字上传图片

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Golang中拼接字符串的6种方式性能对比

《Golang中拼接字符串的6种方式性能对比》golang的string类型是不可修改的,对于拼接字符串来说,本质上还是创建一个新的对象将数据放进去,主要有6种拼接方式,下面小编就来为大家详细讲讲吧... 目录拼接方式介绍性能对比测试代码测试结果源码分析golang的string类型是不可修改的,对于拼接字

Nginx实现前端灰度发布

《Nginx实现前端灰度发布》灰度发布是一种重要的策略,它允许我们在不影响所有用户的情况下,逐步推出新功能或更新,通过灰度发布,我们可以测试新版本的稳定性和性能,下面就来介绍一下前端灰度发布的使用,感... 目录前言一、基于权重的流量分配二、基于 Cookie 的分流三、基于请求头的分流四、基于请求参数的分

mysql线上查询之前要性能调优的技巧及示例

《mysql线上查询之前要性能调优的技巧及示例》文章介绍了查询优化的几种方法,包括使用索引、避免不必要的列和行、有效的JOIN策略、子查询和派生表的优化、查询提示和优化器提示等,这些方法可以帮助提高数... 目录避免不必要的列和行使用有效的JOIN策略使用子查询和派生表时要小心使用查询提示和优化器提示其他常

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录