首先,性能优化分好几个方面,本章我们从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。

Web篇之JS性能优化的更多相关文章

  1. js 性能优化 篇一

    JS性能优化 摘自:http://www.china125.com/design/js/3631.htm  首先,由于JS是一种解释型语言,执行速度要比编译型语言慢得多.(注:,Chrome是第一款内 ...

  2. js性能优化文章集锦

    总结的js性能优化方面的小知识http://www.it165.net/pro/html/201503/35336.html 如何优化你的JS代码http://www.php100.com/html/ ...

  3. js性能优化-事件委托

    js性能优化-事件委托 考虑一个列表,在li的数量非常少的时候,为每一个li添加事件侦听当然不会存在太多性能方面的问题,但是当列表非常的长,长到上百上千甚至上万的时候(当然只是一个解释,实际工作中很少 ...

  4. 原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(10年前数百篇oracle/teradata性能优化、故障处理案例)

    原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(数百篇oracle/teradata性能优化.故障处理原创文章) 858871 top 500 ...

  5. js 性能优化利器:prepack

    1. js 性能优化 js 本身是没有像 python 一样的预编译功能,更没有像 java 一样的编译功能,所以,这里所说的 js 代码预编译 只是通过工具实现的类似功能而已. 这就要提到 prep ...

  6. 从web现状谈及前端性能优化

    从web现状谈及性能优化 原文出处:<Karolina Szczur: The State of the Web> 性能优化指南The Internet is growing expone ...

  7. JS性能优化笔记搜索整理

    通过网上查找资料了解关于性能优化方面的内容,现简单整理,仅供大家在优化的过程中参考使用,如有什么问题请及时提出,再做出相应的补充修改. 一. 让代码简洁:一些简略的表达方式也会产生很好的优化 eg:x ...

  8. 全方位分析web前端如何进行性能优化

    前言: 最近刚刚完成项目,空闲一段时间,想起之前有被问起怎么对前端进行性能优化,自己也是脑中零零散散的总不成体系,现特来总结,欢迎补充指教. 1.整体资源 (1)js.css源码压缩 (2)css文件 ...

  9. 你不知道的Node.js性能优化,读了之后水平直线上升

    本文由云+社区发表 "当我第一次知道要这篇文章的时候,其实我是拒绝的,因为我觉得,你不能叫我写马上就写,我要有干货才行,写一些老生常谈的然后加上好多特技,那个 Node.js 性能啊好像 D ...

随机推荐

  1. PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类

    摘要 分型是计算生物学的一个新兴领域,在临床决策和生物医学科学中有着重要的应用. 虽然机器学习技术在许多生物医学应用中显示出巨大的潜力,但它们在分型中的用途尚未完全理解. 在本文中,我们研究了基于聚类 ...

  2. Greeplum 系列(一) Greenplum 架构

    Greeplum 系列(一) Greenplum 架构 Greenplum 可进行海量并行处理 (Massively Parallel Processing) 一.Greenplum 体系架构 Gre ...

  3. Linux之chmod使用

    Linux文件分三种身份和四中权限. u:文件的拥有者 g:文件所属的群组 o:其他用户 对于每个身份,又有四种权限,分别为: r:读取文件的权限(read) w:写入文件的权限(write) x:执 ...

  4. stl源码分析de练习

    // StlTest1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <vector> #include & ...

  5. oracle RAC 创库,停启库,删除库

    1.创建数据库的命令dbca -silent -createDatabase -templateName General_Purpose.dbc -gdbname FPCSDB2 -sid FPCSD ...

  6. CMD 与 ENTRYPOINT 的区别

    Dockerfile里有 CMD 与 ENTRYPOINT 两个功能咋看起来很相似的指令,开始的时候觉得两个互用没什么所谓,但其实并非如此: CMD指令: The main purpose of a ...

  7. linux每天一小步---cat命令详解

    1 命令功能 cat命令是linux系统下的一个文本输出命令,通常用于查看文件的内容. 2 命令语法 cat  [选项参数]  文件名 3 命令参数 -n  由1开始对所有输出的内容行数编号 -b   ...

  8. [label][JavaScript][The Defined Guide of JavaScript] 变量的作用域

    变量的作用域 一个变量的作用域(scope)是程序中定义这个变量的区域. 全局(global)变量的作用域(scope)是全局性的,即在JavaScript代码中,它处处都有定义.    而在函数之内 ...

  9. ASP.NET Core 2.0 in Docker on Windows Containers

    安装Docker for Windows https://store.docker.com/editions/community/docker-ce-desktop-windows 要想将一个ASP. ...

  10. 当我们在谈论multidex65535时,我们在谈论什么

    本文来自网易云社区 作者:郑文 首先我们并不在讨论车牌号.本文尽量避免谈论重复的技术点,只探讨一下multidex提供给我们的技术启示. 原理 multidex技术原理可以分成两个部分: 在app启动 ...