• 前端性能优化之管理后台列表功能操作


    背景

    之前做的一个后台管理项目,在开发的时候,由于开发时间比较紧,所以在对列表做更新和删除操作的时候,
    操作成功需要更新页面数据,当时我是直接通过再次获取接口数据进行页面的更新,其实这样是有性能问题的,
    造成了服务器不必要的浪费,而且体验非常不好,页面会出现闪屏。

    优化解决过程

    本着从每一个细节做好的原则,所以今天抽时间对这块做了个优化,不需要再次获取接口数据,而是在操作
    成功后,通过js的splice数组方法来对数据进行修改和删除,这样对性能有了一个提升,而且用户体验也变
    的非常好。

    这个是一个权限菜单列表的优化,一开始我以为会很好处理,后来发现这跟其他的列表还不太一样,这是一个树形的列表,意味着层级关系比较多,
    所以我开始的想法是遍历整个菜单列表数据,然后通过当前操作对象id去寻找然后来移除或更新项目,但这样感觉很麻烦,后来就去看ElementUI框架(使用的是这个框架)官方文档,
    发现它提供了一个当前节点的 Node 对象,参考http://element.eleme.io/#/zh-CN/component/tree中的render-content,
    那这样就好办了,我们通过node.parent.data来获取到数组对象,然后进行遍历

     const parent = node.parent;
     const children = parent.data.children || parent.data;
    

    这里需要注意的事,如果操作的是一级菜单,返回的是一个json数组格式,而如果是二级菜单则返回的
    是一个对象json格式

    一级菜单返回json

    [{
        "id":"4",
        "menu_name":"权限管理",
        "flag":"authority",
        "is_display":"y",
        "parent_flag":"",
        "parent_id":"0",
        "order_num":"9000",
        "level":"1",
        "dt":"2015-06-18 13:49:32",
        "is_del":"n",
        "del_dt":"0000-00-00 00:00:00",
        "sub":Array[2]
      }]
    

    二级菜单返回json

    {
        "id":"225",
        "menu_name":"caidan4",
        "flag":"ces_menu4",
        "is_display":"n",
        "parent_flag":"ces",
        "parent_id":"221",
        "order_num":"0",
        "level":"2",
        "dt":"2018-03-16 20:20:01",
        "is_del":"n",
        "del_dt":null,
        "sub":[
    
        ]
      }
    

    这里通过instanceof来判断是否是数组,然后重新赋值

      let newArr = children.sub;
                            if(children instanceof Array){
                                newArr = children;
                            }
    

    这里主要用到js的splice这个方法 ,从数组中删除一个对象

    newArr.splice(index, 1);
    

    splice方法是从数组中添加/删除项目,返回被删除的项目。
    第一个参数是要删除项目的索引,第二个参数表示删除的数量,如果设置为0,则不删除。
    需要注意的是该方法会改变原始数组

    优化前的代码:

    delMenu(node,p_data){
                    api.authority_menu_del({
                        id:p_data.id
                    })
                    .then((data)=>{
                        // console.log(data)
                        var _data = util.formatJson(data);
                        if (_data.code == 0) {
                            this.$message({
                                message: '删除成功',
                                type: 'success'
                            });
                            this.load_list();
                        }else{
                             this.$message.error(_data.message);
                        }
                    })
                    .catch((error)=>{
                        this.$message.error({
                            message: '未知错误,请联系管理员!'
                        });
                    })
                },
    

    优化后的代码:

    delMenu(node,p_data){
                    api.authority_menu_del({
                        id:p_data.id
                    })
                    .then((data)=>{
                        // console.log(data)
                        var _data = util.formatJson(data);
                        if (_data.code == 0) {
                            this.$message({
                                message: '删除成功',
                                type: 'success'
                            });
                            //直接删除该节点对象  而不是重新请求数据刷新this.load_list();
                            const parent = node.parent;
                            const children = parent.data.children || parent.data;
                            let newArr = children.sub;
                            if(children instanceof Array){
                                newArr = children;
                            }
                            newArr.forEach((element,index) => {
                                if(element.id==p_data.id){
                                    newArr.splice(index, 1);//通过索引删除对象
                                }
                            });
                        }else{
                             this.$message.error(_data.message);
                        }
                    })
                    .catch((error)=>{
                        this.$message.error({
                            message: '未知错误,请联系管理员!'
                        });
                    })
                },
    

    以上是对删除操作做的优化,下面还有个对更新操作做的优化

    //直接修改该节点对象  而不是重新请求数据刷新this.load_list();
                            const parent = this.addOrUpdateNode.parent;
                            const children = parent.data.children || parent.data;
                            // console.log(JSON.stringify(children))
                            let newArr = children.sub;
                            if(children instanceof Array){
                                newArr = children;
                            }
                            newArr.forEach((element,index) => {
                                if(element.id==this.form.id){
                                    newArr[index].id = this.form.id;
                                    newArr[index].menu_name = this.form.menu_name;
                                    newArr[index].menu_flag = this.form.menu_flag;
                                    newArr[index].is_display = this.form.is_display;
                                    newArr[index].order_num = this.form.order_num;
                                    newArr.splice(index,1,newArr[index]);
                                }
                            });
    

    可以看到跟上面的代码差不多,也是通过splice来做的优化

     newArr.splice(index,1,newArr[index]);
    

    根据索引先删除一个项目,然后再向数组添加一个新的项目

    关于js判断是否数组主要有三种方式 参考http://www.jb51.net/article/79939.htm

    1.使用typeof
    2.instanceof
    3.原型链方法
    这里typeof有个问题

    //首先看代码
    var ary = [1,23,4];
    console.log(typeof ary); //输出结果是Object
    

    这个并不能实时的检测出是否是数组,只能判断其类型,所以说typeof判断基本类型数据还是挺好的,但是不能准确测试出是否是数组

    instanceof使用

    var ary = [1,23,4];
    console.log(ary instanceof Array)//true;
    

    原型链方法

    var ary = [1,23,4];
    console.log(ary.__proto__.constructor==Array);//true
    console.log(ary.constructor==Array)//true 这两段代码是一样的
    

    但是,这个是有兼容的哦,在IE早期版本里面__proto__是没有定义的

    而第2,3种方法仍然有局限性,这里有个通用的原型链方法

    var ary = [1,23,4];
    function isArray(o){
    return Object.prototype.toString.call(o)=='[object Array]';
    }
    console.log(isArray(ary));
    

    总结

    虽然是一个后台管理系统,仅仅是公司内部人员使用,对性能和体验要求不是很高,但是作为一个好的开发
    人员,我觉得应该要养成一个好习惯,做好每一个细节,在时间满足的前提下,把事情做的最好,这样不仅仅能
    够提升自己,而且把事情做完美了,领导也会对你有所赏识,何乐而不为呢 。

    作者:fozero
    声明:原创文章,转载请注明出处,谢谢!http://www.cnblogs.com/fozero/p/8586137.html
    标签:性能优化,总结

  • 相关阅读:
    jQuery插件之jqzoom
    python数据分析画图体验
    python正则表达式,以及应用[下载图片]
    Python 程序如何高效地调试?
    从汉诺塔游戏理解python递归函数
    Python文本文件的输入输出操作学习
    Windows搭建python开发环境
    python循环综合运用
    Python参数传递,既不是传值也不是传引用
    使用python实现用微信远程控制电脑
  • 原文地址:https://www.cnblogs.com/fozero/p/8586137.html
Copyright © 2020-2023  润新知