性能优化紧急回顾笔记

最近无聊,又开始刷书,写写《高性能JavaScript》读后感吧!

 

1、脚本加载

  脚本加载会阻塞其他文件下载,页面会等到所有JavaScript代码下载并执行完成才能继续

  解决方法:(1)、建议将script标签放在body底部,确保脚本执行前页面已完成渲染

       (2)、可以将某些脚本直接写在script标签插入html中,进行首屏优化

       (3)、使用webpack等工具打包或压缩代码,减少请求与文件体积

 

2、数据存取

  数据有四种方式,字面量、本地变量、数组、对象

  多层引用,例如window.location.href、原型链搜索等,如果使用多次,建议进行本地储存

  比如:h = window.location.href

 

3、DOM

  DOM操作很慢,原因有2:DOM节点很复杂、修改DOM会导致重绘(repaint)和重排(reflow)

  (1)、插入节点推荐使用innerHTML,大量字符串建议使用数组拼接

  (2)、HTMLCollection集合是动态检测,如果对象更新,对应的集合也更新,无论是获取还是修改都会触发一次

  (3)、比较通用的优化方法,缓存(类)数组长度,再进行循环遍历操作

  (4)、重排、重绘都是代价昂贵的操作,尽量减少发生。

  (5)、事件委托

tips:重绘、重排

  浏览器下载完页面中所有组件-HTML标记、JavaScript、CSS、图片-之后(这里有误,边下载边渲染)会解析并生成两个内部数据结构:

  DOM树 => 表示页面结构

  渲染树 => 表示DOM节点如何显示

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

  当DOM变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性。浏览器会使渲染树中受到影响的部分失效,重新构造渲染树,这个过程叫‘重排(reflow)’;完成重排后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为‘重绘(repaint)’。

  当改变颜色时,只会引起重绘。

  重排发生条件:

  1、添加、删除可见元素

  2、元素位置改变

  3、元素尺寸改变

  4、内容改变

  5、页面渲染初始化

  6、浏览器窗口尺寸改变

  浏览器会通过队列化修改(类似于task)来优化重排过程。然而,当获取类似于offsetTop、getComputedStyle等属性时,会强制浏览器渲染已获取最近属性。

  当需要对DOM做多次操作时,有三种方式优化:

  1、将DOM隐藏,操作完后显示

  2、构建文档碎片,插入DOM(推荐)

  3、创建一个DOM备份,操作完后替换原DOM

 

4、算法与流程

  (1)、倒序+缓存长度优化循环: 

    // 某数组
    var arr = [];
    // 循环处理元素
    for (var i = 0; i < arr.length; i++) {
        process(arr[i]);
    }
    // 优化循环体
    for (var i = arr.length; i--;) {
        process(arr[i]);
    }

   

  (2)、贴一个Duff's Device,通过分割循环次数提升效率:

    // Duff's Device
    var iterations = Math.floor(items.length / 8), // 表示多少轮循环
        startAt = items.length % 8, // 8的余数
        i = 0; // 从0开始迭代
    do {
        // 首次执行把余数消灭
        switch (startAt) {
            case 0:
                process(items[i++]);
            case 7:
                process(items[i++]);
            case 6:
                process(items[i++]);
            case 5:
                process(items[i++]);
            case 4:
                process(items[i++]);
            case 3:
                process(items[i++]);
            case 2:
                process(items[i++]);
            case 1:
                process(items[i++]);
        }
        startAt = 0;
    } while (--iterations);

  优化后的算法,取消了switch语句,将余数与整数分别处理:

    // 余数
    var i = item.length % 8;
    while (i) {
        process(item[i--]);
    }
    // 整数
    i = Math.floor(item.length / 8);
    while (i) {
        process(items[i--]);
        process(items[i--]);
        process(items[i--]);
        process(items[i--]);
        process(items[i--]);
        process(items[i--]);
        process(items[i--]);
        process(items[i--]);
    }

  

  (3)、if-else与switch

  条件增加时,优化使用switch,性能与代码可读性方面都更好。(在JS中switch使用全等,没有隐式类型转换带来的损耗)

  优化if-else:将最可能出现的情况放在第一项

 

  (4)、查找表

  使用数组或普通对象来构建查找表。

 

5、Ajax

请求:  

  (1)、正常ajax请求

  使用XHR时,POST与GET的对比。

  对于不会改变服务器状态,只会获取数据(幂等行为)的请求,应该使用GET,GET请求的数据会被缓存起来,多次请求有助于提高性能。

  当URL加上参数长度过长使用POST。

 

  (2)、动态脚本注入

  这种技术克服了XHR最大限制:不能跨域。

  该方法通过创建一个script标签, 将src设置为不同域的URL。

  动态脚本注入的控制有限,无法设置请求头,只能通过get传参。

 

缓存:

  (1)、在服务端,设置HTTP头信息以确保你的响应会被浏览器缓存

  通过get方式发送请求,并在响应中发送正确的HTTP头信息,Expires头信息会告诉浏览器缓存响应多久。

  (2)、在客户端,把获取到的信息存储到本地,从而避免再次请求

  

6、finally

  (1)、文件合并(webpack)

  (2)、文件压缩

  (3)、缓存

  (4)、CDN

 

  完结撒花!

posted @ 2017-03-19 21:44  书生小龙  阅读(199)  评论(0编辑  收藏  举报