文档章节

Web篇之JS性能优化

o
 osc_fmg49rzg
发布于 2019/03/20 23:06
字数 1648
阅读 12
收藏 0

精选30+云产品,助力企业轻松上云!>>>

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

 


 

1:垃圾收集

 

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

 

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

let element = document.getElementById("test");
let myObject = 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代码
<ul id="myLinks">
    <li id="goSomeWhere">Go somewhere</li>
    <li id="sayHi">Say hi</hi>
</ul>


//分别加上事件处理-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的点击事件变为了空事件处理程序
<div id="myDiv">
    <input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
    let btn = document.getElementById("myBtn");
    btn.onclick = function(){
      document.getElementById("myDiv").innerHTML = "xxxx";  
    };
</script>

//改善点即需要手工移除事件处理程序
<div id="myDiv">
    <input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
    let btn = document.getElementById("myBtn");
    btn.onclick = function(){
      btn.onclick = null;
      document.getElementById("myDiv").innerHTML = "xxxx";  
    };
</script>

 


 

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+= "<li>Item " + i + "</li>"  
}


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

for (i = 0; i < 10; ++i){
  html += "<li>Item " + i + "</li>"  
}

list.innerHTML = html

 

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

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
前端资源系列(4)-前端学习资源分享&前端面试资源汇总

特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方...

xzavier
2018/08/27
0
0
极客时间-左耳听风-程序员攻略-前端基础和底层原理

前端基础和底层原理 对于前端的学习和提高,前端的三个最基本的东西 HTML 5、CSS 3 和 JavaScript(ES6)是必须要学好的。这其中有很多很多的技术,比如,CSS 3 引申出来的 Canvas(位图)、...

osc_2h38v7rr
2019/08/06
1
0
前端语言学习干货合集!

前端开发是创建Web页面或app等前端界面呈现给用户的过程。前端开发通过HTML,CSS及JavaScript以及衍生出来的各种技术、框架、解决方案,来实现互联网产品的用户界面交互 。 为了让营造一个针...

燕儿😘
2019/01/14
0
0
JavaScript为什么快--第一篇?

为啥升级了NodeJS版本,速度会提升? 为啥NodeJS代码启动时那么慢,运行起来了会变快? V8 JIT是啥? 前言 V8的产品定义:Speed up real-world performance for modern JavaScript, and enab...

秦粤
2018/08/02
0
0
JavaScript为什么快--第一篇?

摘要: V8让JavaScript更快的秘密;V8的JavaScript执行管道;TurboFan&Ignition 为啥升级了NodeJS版本,速度会提升? 为啥NodeJS代码启动时那么慢,运行起来了会变快? V8 JIT是啥? 前言 V8...

阿里云云栖社区
2018/08/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

MongoDB入门系列——3.可视化工具篇

点击上方,轻松关注!! 前面我们已经介绍了MongoDB怎么安装,接下来要安装他的可视化工具——Studio 3T。 先到这下载一个压缩包,百度网盘,https://pan.baidu.com/s/1M8mlWo334KE8I1_UA2Da...

学习Java的小姐姐
2018/11/08
0
0
分层图的绘制 python(来自国外课程)

Exercise 10: Hierarchical clustering of the grain data In the video, you learnt that the SciPy linkage() function performs hierarchical clustering on an array of samples. Use th......

齐勇cn
25分钟前
13
0
微信小程序超简单的双向绑定(类似vue的v-model)

<input model:value="{{value}}" />

祖达
26分钟前
9
0
为什么AngularJS在select中包含一个空选项? - Why does AngularJS include an empty option in select?

问题: I've been working with AngularJS for the last few weeks, and the one thing which is really bothering me is that even after trying all permutations or the configuration de......

技术盛宴
29分钟前
13
0
centos宝塔面板安装及常见错误处理(超级详细)

原文连接:https://www.wjcms.net/archives/centos%E5%AE%9D%E5%A1%94%E9%9D%A2%E6%9D%BF%E5%AE%89%E8%A3%85%E5%8F%8A%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E8%B6%85%E7%......

神兵小将
50分钟前
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部