zoukankan      html  css  js  c++  java
  • 高性能javascript

    高性能javascript开发

    标签(空格分隔): javascript


    DOM访问与修改

    访问DOM元素是具有代价的,修改元素代价较为昂贵,会导致浏览器重新计算页面的几何变化。

    尽量减少DOM访问,做好缓存。

    HTML集合&遍历DOM

    操作DOM的一个消耗点是遍历DOM,在使用getElementsByTagName(),document.links等时,会收集一个类似数组的集合。这个数组处于一个"实时状态",会自动更新。

    <ul id="fruit">
        <li>apple</li>
        <li>orange</li>
        <li>banana</li>
    </ul>
    <script>
        var lis = document.getElementByTagName('li');
        var peach = document.createElement('li');
        peach.innerHTML = 'peach';
        document.getElementById('fruit').appendChild(peach);
        console.log(lis.length);//4
        //这里获取length会比普通数组获取length时间长很多
    </script>
    

    优先使用querySelector()和querySelectorAll()

    虽然上面的两个方法不一定就比集合的方法快,但是本身的语法很好,类jquery。支持css选择器。

    重绘repaint和重排,回流reflow

    浏览器在下载完页面所有组件后,会解析成生成两个内部数据结构----DOM树和渲染树。

    DOM树负责表示页面结构渲染树负责表示DOM节点如何显示

    DOM树中的每一个显示的节点在渲染树中至少存在一个对应的节点(隐藏的DOM元素display为none在渲染树中没有对应的节点)。

    渲染树中的节点被称为“帧”或“盒”,符合css盒模型的定义,理解页面元素为一个具有填充,边距,边框和位置的盒子。一旦DOM树和渲染树构建完成,浏览器就开始显示(绘制)页面元素。

    重排:当DOM元素的变化影响了元素的几何属性(高或宽)时,浏览器就需要重新计算元素的几何属性,那么其他的元素的位置和几何属性也会受到影响。浏览器的渲染树部分失效,触发了浏览器重新构造渲染树。

    重绘:完成重排后,浏览器会重新绘制受影响的部分到屏幕。

    由于浏览器的流布局,对渲染树计算通常只需遍历一次即可。但table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树节点中的属性,通常花费的时间是同等元素的3倍。所以我们不用table元素布局。

    发生重排就会发生重绘,但是也可能只发生重绘。
    比如我们只对DOM元素操作其背景色,那么就只会发生重绘,不涉及几何元素就不会发生重排。

    重绘和重排的代价会有多大?

    我们用代码来说明:

    var times = 15000;
    console.time(1);
    for (var i = 0; i < times; i++) {
    	document.getElementById('div1').innerHTML += 'a'; 
    }
    console.timeEnd(1);
    
    console.time(2);
    var str = '';
    for (var i = 0; i < times; i++) {
    	var tmp = document.getElementById('div2').innerHTML;
    	str += 'a';
    }
    document.getElementById('div2').innerHTML = str;
    console.timeEnd(2);
    
    console.time(3);
    var str1 = '';
    for (var i = 0; i < times; i++) {
    	str1 += 'a';
    }
    document.getElementById('div3').innerHTML = str1;
    console.timeEnd(3);
    
    1: 4382.324ms
    2: 6.485ms
    3: 1.565ms
    

    DOM操作其实不是很可怕,消耗的性能也不是那么大,最重要的重绘和重排。

    重排什么时候发生

    上面说到重排必然导致重绘,那么那些操作会导致重排?
    1、添加或删除可见DOM元素;
    2、元素的position位置改变;
    3、元素的尺寸改变;
    4、内容改变;
    5、页面渲染初始化;
    6、浏览器窗口尺寸改变;(这个就恶心了,页面说不定会挂掉)

    怎么提升性能

    浏览器队列

    其实浏览器也没有那么傻,它会做很多的工作,一般来说,浏览器会做一个队列,当你要使用这些改变时,它才会去页面中改变。不然,它不会一个一个的去执行这些操作,而是会一起变化,以减小页面的重绘重排。
    会刷新队列的操作比如:
    1、offsetTop,offsetLeft,offsetWidth,offsetHeight
    2、scrollTop,scrollLeft,scrollWidth,scrollHeight
    3、clientTop,clientLeft,clientWidth,clientHeight
    4、getComputedStyle(),(currentStyle in IE)

    cssText

    如果真的需要获取样式怎么办,我们使用cssText方法,一次性改变所有的style。
    css.style.cssText,在这里需要注意CSSText会覆盖之前的style。或者使用className。

    var ele = document.getElementById('div');
    ele.style.cssText = ".."//这里重写css
    ele.style.cssText += ""//这里添加css
    
    ele.className = "active"
    

    fragment文档碎片

    使用fragment文档碎片也可以解决这类问题。

    脱离动画流

    1、使用绝对位置定位页面上的动画元素,将其脱离文档流。

    总结

    1、尽量不要在布局信息改变时做查询(会导致渲染队列强制刷新)
    2、同一个DOM的多个属性改变可以写在一起(减少DOM访问,同时把强制渲染队列刷新的风险降为0)
    3、如果要批量添加DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排(fragment元素的应用)
    4、将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位

    参考文献:
    1、韩子迟的博客;

  • 相关阅读:
    shell脚本练习
    Linux 在线模拟器
    附件2:async/await
    附件1:setTimeout与闭包
    Java基础复习(二、String相关)
    Java基础复习(一、数据类型)
    Java的自动装箱和拆箱
    牛客网
    创建新模块时遇到的几个问题
    Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
  • 原文地址:https://www.cnblogs.com/thecatshidog/p/5639700.html
Copyright © 2011-2022 走看看