web性能优化

Web篇之JS性能优化

首先,性能优化分好几个方面,本章我们从js方面来优化。

1:垃圾收集


日常中的某些情况下垃圾收集器无法回收无用变量,导致的一个结果就是——内存使用率不断增高,以下为对应的情况以及处理方法。


①对象相互引用会导致引用计数始终为2,所以用完对象后应将引用设为null,例子如下

letelement = document.getElementById("test");letmyObject =new Object();

myObject.element = element;

element.someObject = myObject;

//....用完后需要加如下代码

myObject.element = null;

element.someObject = null;

②当数据不再有用时,需要通过将值设为null来解除引用,该做法适用于大多数全局变量和全局对象属性,例子如下

function createPerson(name){

    let localPerson =new Object();

    localPerson.name = name;

    return localPerson

}

let globalPerson = createPerson("test")//...用完后手动解除globalPerson =null

③关于与闭包相关的内存泄漏如下

function assignHandler(){

  let element = document.getElementById("test");

  element.onclick =function(){

    alert(element.id)   

  }         

}//以上会导致element的引用数无法被回收,更改如下function assignHandler(){

  let element = document.getElementById("test");

  let id = element.id;

  element.onclick =function(){

    alert(id)

  }         

  element =null; 

}

2:事件委托

在js中,添加到页面上的事件处理程序数量会直接关系到页面整体运行运行性能。导致这一问题的原因是多方面的。首先函数都是对象,都会占用内存;内存中对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。以下为对应的情况以及处理方法

①同类型的事件处理函数过多时,应该结合为一个,例子如下:

//html代码

       
  • Go somewhere
  •    
  • Say hi
//分别加上事件处理-JS代码

let item1 = document.getElementById("goSomeWhere");

let item2 = document.getElementById("sayHi");

EventUtil.addHandler(item1, "click",function(event){

  console.log("goSomeWhere") 

}

EventUtil.addHandler(item2, "click",function(event){

  console.log("sayHi"); 

}//改善点即将click事件结合在一起let list = document.getElementById("myLinks")

EventUtil.addHandler(list, "click",function(event){

  event = EventUtil.getEvent(event);

  let target = EventUtil.getTarget(event);


  switch(target.id){

    case"goSomeWhere":

      console.log("goSomeWhere");

      break;

  case"sayHi":

      console.log("sayHi");   

      break;           

  }   

}

②内存留有过时不用的“空事件处理程序”也是造成性能问题的主因,两种情况下会造成该问题。运用removeChild()和replaceChild()方法去除节点时;在使用innerHTML替换页面某一部分时,如果带有事件处理程序的元素被innerHTML删除了,那么原有事件处理函数极有可能无法被回收,例子如下

//例子中id为myBtn的点击事件变为了空事件处理程序    let btn = document.getElementById("myBtn");

    btn.onclick =function(){

      document.getElementById("myDiv").innerHTML = "xxxx"; 

    };//改善点即需要手工移除事件处理程序    let btn = document.getElementById("myBtn");

    btn.onclick =function(){

      btn.onclick =null;

      document.getElementById("myDiv").innerHTML = "xxxx"; 

    };

3:注意作用域

关于作用域链,我们明白访问全局变量会比访问局部变量要慢

①若某处循环使用全局变量时,我们可以略做修改,例子如下

//假设有多个img标签的内容,循环中引用了多次document全局变量function updateUI(){

  let imgs = document.getElementsByTagName("img")

  for(let i = 0; len = imgs.length; i < len; ++i){

    imgs[i].title = document.title + " image “ + i 

  }   

  let msg = document.getElementById("msg");

  msg.innerHTML = "Update";   

}

//改善点

function updateUI(){

  let doc = document

  let imgs = doc.getElementsByTagName("img")

  for (let i = 0; len = imgs.length; i < len; ++i){

    imgs[i].title = doc.title + " image “ + i 

  }   

  let msg = doc.getElementById("msg");

  msg.innerHTML = "Update";   

}

②尽量少用with,因为with会增加其中执行代码的作用域链的长度

4:选择正确方法

首先,我们要了解JS中算法的复杂度

标记名称 描述

O(1)常数不管有多少值,执行的时间都是恒定的。一般表示简单值和存储在变量中的值

O(log n)对数总的执行时间和值的数量相关,但是要完成算法并不一定要获取每个值。例如:二分查询

O(n) 线性总执行时间和值的数量直接相关。例如:遍历某个数组中的所有元素

O(n^2)平方总执行时间和值的数量有关,每个值至少要获取n次。例如:插入排序

常数值和访问数组元素操作都是O(1)操作;对象属性查找操作是O(n)操作;

let values =  [5, 10]; let sum = values[0] + values[1]属于O(1)操作;let values = window.location.href属于O(2)操作

①遇到有多次属性查询的场合,可以考虑是否能做优化,例子如下

//这里总共做了6次属性查询,其中window.location.href.substring与window.location.href.indexOf分别为3次let query = window.location.href.subsring(window.location.href.indexOf("?"))//改善, 第一次访问时复杂度会是O(n),但该版本只有4次属性查询,相对于原始版本节省了33%let url = window.location.href;

let query = url.substring(url.indexOf("?"));

②循环优化,这里其实用后测试循环代替前测试循环会更好,不过本地不采用,例子如下

//原有复杂度为O(n)for(let i = 0; i < values.length; ++i){

  process(values[i]); 

}//更改后复杂度为O(1)for(let i = values.length - 1; i >= 0; --i){

  process(values[i]) 

}

③最小化语句数相关

例如进行多个声明时,我们可以进行组合,例子如下

//多个声明

let count = 5;

let color = "blue";

let values = [1, 2, 3];//组合成一个let count = 5,

    color = ”blue",

    values = [1, 2, 3]

例如插入迭代值时,例子如下

//修改前

let name = values[i];

i++;//修改后let name = values[i++]

使用数组和对象字面量时,例子如下

//修改前

let values =new Array();

values[0] = 123;

values[1] = 456;

values[2] = 789;

let person =new Object();

person.name = "Eric";

person.age = 20;//修改后let values = [123, 456, 789]

let person = {

  name: "Eric",

  age:20,   

}

④创建DOM节点最好使用innerHTML方法,因为innerHTML设置值时,后台会创建HTML解析器,然后使用内部的DOM调用来创建DOM结构,而非基于JS的DOM调用。

调用一次innerHTML,就会进行一次现场刷新,循环插入DOM结构时,应注意尽量调用少次数的innerHTML,代码如下

//错误方法,做了很多次现场刷新

let list = document.getElementById("myList"),

    i;for(i = 0; i < 10; ++i){

  list.innerHTML = html+= "

  • Item " + i + "
  • }//正确方法,尽管在字符串连接上有性能损失,但却只做了一次现场刷新let list = document.getElementById("myList"),

        html = "",

        i;for(i = 0; i < 10; ++i){

      html += "

  • Item " + i + "
  • }

    list.innerHTML = html

    ⑤其他如有多个if-else语句时,应尽可能转为Switch语句;用appendChild()插入元素时,应采用自上而下插入;面向对象编程时,应合理释放内存,设object为null。

    ©著作权归作者所有,转载或内容合作请联系作者
    • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
      沈念sama阅读 217,277评论 6 503
    • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
      沈念sama阅读 92,689评论 3 393
    • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
      开封第一讲书人阅读 163,624评论 0 353
    • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
      开封第一讲书人阅读 58,356评论 1 293
    • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
      茶点故事阅读 67,402评论 6 392
    • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
      开封第一讲书人阅读 51,292评论 1 301
    • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
      沈念sama阅读 40,135评论 3 418
    • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
      开封第一讲书人阅读 38,992评论 0 275
    • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
      沈念sama阅读 45,429评论 1 314
    • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
      茶点故事阅读 37,636评论 3 334
    • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
      茶点故事阅读 39,785评论 1 348
    • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
      沈念sama阅读 35,492评论 5 345
    • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
      茶点故事阅读 41,092评论 3 328
    • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
      开封第一讲书人阅读 31,723评论 0 22
    • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
      开封第一讲书人阅读 32,858评论 1 269
    • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
      沈念sama阅读 47,891评论 2 370
    • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
      茶点故事阅读 44,713评论 2 354

    推荐阅读更多精彩内容