JavaScript高性能编码知识记录

想必大家都知道,JavaScrip是全栈开发语言,浏览器,手机,服务器端都可以看到JS的身影。本文记录的一些信息,纯属其他地方汇总。看看,了解一些。

数据存储

计算机学科中有一个经典问题是通过改变数据存储的位置来获得最佳的读写性能,在JavaScript中,数据存储的位置会对代码性能产生重大影响。

  • 能使用{}创建对象就不要使用new Object , 能使用[]创建数组的就不要使用new Array。JS中字面量的访问速度要高于对象(有待验证)。
  • 变量在作用域链中的位置越深,访问所需时间越长。对于这种变量,可以通过缓存使用局部变量保存起来,减少对作用域链的访问次数(可以通过参数的形式,把变量传入)。

循环 ☆

在JS中常见的循环有下面几种:

    for( var i=0 ;i<10 ;i++ ){ // do more }

    for(var i in obj ){ // do more }

    [1,2,3].forEach(function(value,index,array){ // 基于函数的循环   })

第一种方式是原生的,性能消耗最低的,速度也最快。第二种方式for-in 每次迭代都会产生更多的开销(局部变量),它的速度大概是第一种的1/7 , 第三种方式明显提供了更变量的循环方式,但他的速度也只有普通循环的1/8 。其实这些相对请求来说,都是很少的,看自身情况去选择合适的循环方式。
通过时间差进行断定的,上面的数据可能不准,以实际运行的耗时为准。

        var arr = [];
        for(var i =0 ; i<100000; i++){
            arr.push(i);
        }
        console.log(arr);  //one
        var oldTime = new Date().getTime();
       for(var i=0; i<arr.length;i++){
          arr[i]= arr[i]+1;
       }
        var onetime = new Date().getTime() - oldTime;
        console.log("one 耗时"+onetime);      
        var twooldTime = new Date().getTime();
       for(var i=0 in arr){
          arr[i]= arr[i]+1;
       }
        var twotime = new Date().getTime() - twooldTime;
        console.log("two 耗时"+twotime);          
        var threeoldTime = new Date().getTime();
        arr.forEach(function(index, arr){
            arr[index]= arr[index]+1;
        })
        var threeTime = new Date().getTime() - threeoldTime;
        console.log("three 耗时"+threeTime);          
        console.log(arr);

事件委托 ☆

试想一下页面上每一个A标签添加一个事件,我们会不会给每一个标签都添加一个onClick() 事件呢。当页面中存在大量元素都需要绑定同一个事件处理的时候,这种情况可能会影响性能。每绑定一个事件都加重了页面或者是运行期间的负担。对于一个富前端的应用,交互重的页面上,过多的绑定会占用过多内存。一个简单优雅的方式就是事件委托。它是基于事件的工作流:逐层捕获,到达目标,逐层冒泡。既然事件存在冒泡机制,那么我们可以通过给外层绑定事件,来处理所有的子元素触发的事件。
伪代码:

document.getElementById('content').onclick = function(e) { 
    e = e || window.event;    
    var target = e.target || e.srcElement;    //如果不是 A标签,我就退出   
    if(target.nodeNmae !=== 'A') { return }   //打印A的链接地址    
    console.log(target.href) }

验证代码:

//  耗时   28 29
//      var lis = document.querySelectorAll("ul li");
//      var oldTime = new Date().getTime();
//      for(var i=0; i< lis.length;i++){
//          lis[i].onclick = function(){
//              console.log(this);
//          }
//      }
//      var times = new Date().getTime() - oldTime;
//      console.log(times);

//      耗时 2  3 
        var oldTime = new Date().getTime();
        var ul = document.querySelector("ul");
        ul.onclick = function(e){
            if(e.target.nodeName =="LI"){
                console.log(e.target)
            }
        }
        var times = new Date().getTime() - oldTime;
        console.log(times);
    </script>

重绘与重排 ☆

浏览器下载完HTML,CSS,JS后悔生成两棵树:DOM树和渲染树。当Dom的几何属性发生变化时,比如Dom的宽高,或者颜色,position,浏览器需要重新计算元素的几何属性,并且重新构建渲染树,这个过程称为重绘重排。

bodystyle = document.body.style; 
bodystyle.color = red; 
bodystyle.height = 1000px; 
bodystyke.width = 100%;

上述方式修改三个属性,浏览器会进行三次重排重绘,在某些情况下,减少这种重排可以提高浏览器渲染性能。 推荐方式如下,只进行一次操作,完成三个步骤:

bodystyle = document.body.style; 
bodystyle.cssText ='color:red;height:1000px;width:100%';

或者使用增加类名的方式实现批量样式修改 ,提前将样式写好,放到css文件中。

    .active{
      width: 100px;
      height: 100px;
      backgroung-color: red;
      border: solid 1px green;
    }

然后给元素赋值className

ele.className +=' active';

使用文档碎片

频繁对dom节点进行操作是非常耗性能的,这个时候就应该用document.createDocumentFragment,文档碎片来统一保存节点,最后一次性放入dom 输中,保证只操作一次dom。提升性能。

// 将字符串转换成 DOM 对象
    function cElem(html) {
        var docfrag = document.createDocumentFragment();
        var div = document.createElement('div');
        div.innerHTML = html;
        while(div.firstChild) {
            docfrag.appendChild(div.firstChild);
        }
        return {
            element: docfrag,
            appendTo: function(dom) {
                dom.appendChild(this.element);
            },
            insertBeforeDom:function(dom){
                dom.insertBefore(this.element,dom.childNodes[0])
            }
        };
    }

减少作用域链查找次数 (少用全局变量)

避免双重解释

双重解释一般在我们使用eval、new Function和setTimeout等情况下会遇到。 不过一般也不用

    var sum, num1 = 1, num2 = 2;   
    function func1(){   
        var start = new Date().getTime();   
        for(var i = 0; i < 10000; i++){   
            var func = new Function("sum+=num1;num1+=num2;num2++;");   
            func();   
        }   
        var end = new Date().getTime();   
        alert("用时 " + (end - start) + " 毫秒");   
    }   

JavaScript加载

IE8,Firefox3.5,Chrome2都允许必行下载JavaScript文件。所以<script>不会阻塞其他标签下载。 遗憾的是,JS下载过程依然会阻塞其他资源的下载,比如图片。尽管最新的浏览器通过允许并行下载提高了性能,但是脚本阻塞任然是一个问题。 因此,推荐将所有的<script>标签放在<body>标签的底部,以尽量减少对整个页面渲染的影响,避免用户看到一片空白。

JS文件高性能部署

既然大家已经知道多个<script>标签会影响页面渲染速度,那么就不难理解“减少页面渲染所需的 HTTP”是网站提速的一条经典法则。 所以,在产品环境下合并所有的JS文件会减少请求数,从而加快页面渲染速度。 除了合并JS文件,我们还可以压缩JS文件。压缩是指将文件中与运行无关的部分进行剥离。剥离内容包括空白字符,和注释。改过程通常可以将文件大小减半。 还有一些压缩工具会将局部变量的长度减小,比如:

var myName = "foo" + "bar";  
//压缩后变成  
var a = "foobar";

缓存JS文件

缓存HTTP组件能极大提高网站回访的用户体验。Web服务器通过“Expires HTTP响应头”来告诉客户端一个资源应该缓存多长时间。当然,缓存也有自己的缺陷: 当应用升级时,你需要确保用户下载到最新的静态内容。这个问题可以通过改变静态资源的文件名来解决。 你可能在产品环境看到浏览器引用jsapplication-20151123201212.js,这种就是以时间戳的方式保存新的JS文件,从而解决缓存不更新问题。

避免空的src和href

当link标签的href属性为空、script标签的src属性为空的时候,浏览器渲染的时候会把当前页面的URL作为它们的属性值,从而把页面的内容加载进来作为它们的值。所以要避免犯这样的疏忽。

函数节流 函数

/**
 * 函数节流
 * @fn {Function} 延迟执行函数
 * @interval {Number} 延迟多久执行,默认值500毫秒
 * */
var throttle = function(fn,interval){
    var _fn = fn || function(){}, //保存需要延迟执行函数的引用
        timer, // 定时器
        firstTime = true ;  // 是否是第一次调用

    return function(){
        var args = arguments,
            that = this,
            if(firstTime){
                _fn.apply(that,args);
                return firstTime = false;
            }
            if(timer){
                return false;
            }
            timer = setTimeout(function(){
                clearTimeout(timer);
                timer = null;
                _fn.apply(that,args);
            },interval || 500);
    }
}

总结

我不生产代码,我只是代码的搬移工,希望对每一个看过博客的同伴,能对每一条进行验证。共同进步。

学习js链接:
http://javascript.ruanyifeng.com/

                             by turbo  2016

猜你喜欢

转载自blog.csdn.net/u010427666/article/details/52079231