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

背景

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

优化解决过程

本着从每一个细节做好的原则,所以今天抽时间对这块做了个优化,不需要再次获取接口数据,而是在操作
成功后,通过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格式

871647-20180316220933728-493672478.png

一级菜单返回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
标签:性能优化,总结

原文地址:https://www.cnblogs.com/twodog/p/12137344.html