js是单线程机制的解释型语言,在必要的时候优化代码的形式可以加快程序的运行
jsbench
jsbench是一个前端代码速度测试网站,可以比较多段代码的运行效率:https://jsbench.me/
优化方式
慎用全局变量
- 全局变量位于全局作用域,在局部作用域中需要逐层向上查找
- 全局变量在全局执行上下文中,会一直存在于作用域栈,直到程序结束才能被GC算法回收
- 局部执行上下文中出现同名变量,则会污染全局变量
缓存全局变量
如果某些全局变量的查找无法避免,那就尝试在局部作用域中缓存它,然后利用缓存的数据进行操作
选取两段代码对dom进行操作,在jsbench中测试如下:
在原型对象上添加附加方法
实例需要使用的方法可以定义在原型对象上而不是构造函数内部
因为构造函数内部声明的方法每次创建实例的时候都需要在内存中创建这个方法,
避开闭包陷阱
由于闭包存在,外部可以对内部作用域的变量进行引用,导致内部作用域无法被释放,造成内存泄漏
内部作用域中不需要的引用要释放掉
<body>
<button id="btn" class="btn">click</button>
<script>
function click(){
let btn = document.getElementById("btn")
btn.onclick = function(){
console.log(btn)
}
}
click()
</script>
</body>
修改为:
<body>
<button id="btn" class="btn">click</button>
<script>
function click(){
let btn = document.getElementById("btn")
btn.onclick = function(){
console.log(btn)
}
btn = null
}
click()
</script>
</body>
for循环优化
使用for循环可以用字面量替代对属性的多次访问
比较两段for循环区别如下
几种循环的时间花销比较
foreach最快,forin最慢
文档碎片优化节点添加
对文档的添加删除会产生回流和重绘,影响页面效率,应该减少对整个文档流的影响
//before
for(let i = 0;i<5;++i){
let span = document.createElement("span")
span.innerHTML = i
document.body.appendChild(span)
}
//after
let fag = document.createDocumentFragment()
for(let i = 0;i<5;++i){
let span = document.createElement("span")
span.innerHTML = i;
fag.appendChild(span)
}
document.body.appendChild(fag)
克隆优化节点
如果页面已有类似节点,可以考虑以克隆的方式代替再次创建
<span id="sp">sx</span>
<script>
//before
for(let i = 0;i<5;++i){
let span = document.createElement("span")
span.innerHTML = i
document.body.appendChild(span)
}
//after
let sp = document.getElementById("sp")
console.log(sp)
for (let index = 0; index < 5; index++) {
let span = sp.cloneNode(false)
span.innerHTML = index
document.body.appendChild(span)
}
</script>
直接量替换new object操作
//before
let arr = new Array()
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
//after
let arr = [1,2,3]
减少层级判断
通过条件提前return 不符合的流程,达到减少条件判断层级嵌套的问题
//判断是否是18岁的小明
//before
function judgeMing(name,age){
if(name==='小明'){
if(age === 18){
console.log('正确')
}
else {
console.log('错误')
}
}
else {
console.log('错误')
}
}
//after
function judgeMing(name,age){
if(name!=="小明"|| age!==18)
console.log('错误')
else {
console.log('正确')
}
}
减少作用域链查找层级
原理和慎用全局变量类似,值得一提的是,为了加快运行效率,会利用局部变量将外部作用域的值缓存,或者重新定义一个值,会加大内存的开销
//before
let name = 'sx'
function foo(){
let getName = ()=>{
console.log(name)
}
}
//after
let name = 'sx'
function foo(){
let name = 'sx2'
let getName = ()=>{
console.log(name)
}
}
采用事件绑定
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
function show(){
console.log('sx')
}
//before
let item = document.getElementsByTagName("li")
for(let i of item){
i.onclick = show
}
//after
let ul = document.getElementsByTagName("ul")
ul[0].addEventListener('click',show,true)
</script>