如何提高javascript性能

2021-03-12  本文已影响0人  Lisa_Guo

一、总原则

减少操作:js引擎,业务代码

本文主要从变量访问和算法逻辑讨论

二、变量访问

数据类型
数据存放的位置不同决定了数据访问的速度不同。JavaScript中有四种基本的数据类型:

  1. 字面量 (Literal values)
    变量存储的是实际数值。JavaScript字面量类型有:字符串,数字,布尔值,对象,数组,函数, 正则表达式,NULL,undefined

  2. 变量 (Vriables)
    用vars声明的变量用于存储数据值

  3. 数据项 (Array items)

  4. 对象成员 (Object members)

NOTES:
a. 前两类存储在栈中,后两项存储在堆中
b. 前两类访问速度高于后两种

作用域
声明一个函数实际是创建一个Function类的实例
在函数创建时,建立一个[[Scope]]的内部属性,定义了该函数可访问的数据,称为作用域链。创建器作用域链 = 全局变量:browser,window, document等
在函数运行时,建立一个‘运行期上下文’的内部属性,定义了该函数运行期间作用域链等执行环境。运行期作用域链 = [[Scope]]作用域链 + 局部变量,参数,this,参数等,按照栈的方式存储

实例1: 定义以下函数

function add(num1, num2) {
  const sum = num1 + num2;
  return sum
}

创建期间的作用域链


image.png

执行函数时作用域链


image.png

实例2: 定义以下闭包

function assignEvents() {
   var id = "123"
   document.getElementById('save-btn').onclick = function(event) {
      saveDocument(id)
   }
}

创建期闭包函数作用域链


image.png

执行期闭包函数作用域链


image.png

结论:变量在作用域链的位置越深越慢,全局最慢,局部最快
提升:用本地局部变量缓存全局变量等访问速度慢的变量

三、优化实例

3.1 局部变量缓存

多次访问document的函数

function initUI(){
  var bd = document.body,
  links = document.getElementsByTagName_r("a"),
  i = 0,
  len = links.length;
  while(i < len){
    update(links[i++]);
  }
  document.getElementById("go-btn").onclick = function(){
    start();
  };
  bd.className = "active"
}

缓存document后

function initUI(){
    var doc = document,
    bd = doc.body,
    links = doc.getElementsByTagName_r("a"),
    i = 0,
    len = links.length;
    while(i < len){
        update(links[i++]);
    }
    doc.getElementById("go-btn").onclick = function(){
        start();
    };
   bd.className = "active";
}

3.2 字符串连接

使运算符时,尽量使用+=,-=、=、=等运算符号,而不是直接进行赋值运算。

实例1
如果是追加字符串,最好使用s+=anotherStr;而不是要使用s=s+anotherStr

实例2
拼接多个字符串

// bad  
x+=a; x+=b; x+=c;

/// good    
x+= a + b + c;

3.3 原型链

对象的继承是通过原型对象实现的

实例1
定义如下对象

var book = {
   title: "High Performance JavaScript",
   publisher: 'Yahoo'
}
原型链为 image.png

实例2
定义如下对象

function Book(title, publisher){
    this.title = title;
    this.publisher = publisher;
}
Book.prototype.sayTitle = function(){
    alert(this.title);
};
var book1 = new Book("High Performance JavaScript", "Yahoo! Press");
alert(book1 instanceof Book); //true
alert(book1 instanceof Object); //true
book1.sayTitle(); //"High Performance JavaScript"
book1.toString(); //"[object Object]"
image.png

结论:对象成员在原型链上的位置越深速度越慢
提升:减少.的操作,缓存对象成员的值

四、算法与流程控制优化

4.1 循环语句

主要进行下面几种优化方案:

1 减少对象成员和数组项查找次数

2 减少迭代次数

3 缓存中间值


for (var i=0; i < items.length; i++){
   process(items[i]);
}

上面的代码每次循环要做的操作:

1. 读取属性:items.length
2. 执行比较:i < items.length
3. 判断条件:i < items.length === true
4. 自加操作:i++
5. 数据查找:items[i]
6. 函数调用:process(items[i])

优化后

for (var i=0, l=items.length; i < l ; i++){
   process(items[i])
}

4.2 条件判断

主要是if-else和switch

1. 将常用的条件放在前面

if (value < 5) {
    //do something
    // <5为高概率事件
} else if (value > 5 && value < 10) {
    //do something
    // 5-10为中概率事件
} else {
    //do something
}

2 查表法
适合大量离散数据的条件判断

| |

优化后


//define the array of results
var results = [result0, result1, result2, result3, result4]
//return the correct result
return results[value];

或使用策略模式

//define the array of resultsvar results = [result0, result1, result2, result3, result4]//return the correct result
return results[value];

五、其他优化技巧

其他参考:
优化 JS 条件语句的 5 个技巧
JS性能优化38条”军规”

上一篇 下一篇

猜你喜欢

热点阅读