前端性能优化-笔记

浏览器从输入url到页面呈现的过程作了哪些事情?

  1. 域名解析:解析输入的域名查找对应的IP地址
1.1查找浏览器自身的DNS缓存
    1.2没有找到条目,浏览器会搜索操做系统自身的DNS缓存
    1.3若是在DNS缓存也没有找到,那么尝试读取hosts文件
       (位于C:\Windows\System32\drivers\etc)
    1.4若是hosts文件也没有找到,浏览器就会发起DNS解析请求,直到找到对应的IP地址
复制代码
  1. TCP请求:
浏览器向web服务器发起TCP链接请求: 发起TCP的3次握手
复制代码
  1. HTTP请求:
浏览器会经过TCP链接向远程服务器发送HTTP请求
复制代码
  1. 服务器端响应HTTP请求:
服务器端处理请求,返回html文件
复制代码
  1. 浏览器解析html文件:
解析html文件,加载js,css,image等静态资源
    向服务器端请求下载,会使用多线程去下载,不一样浏览器之间线程数不同
    能够用上keep-alive特性,创建一次HTTP链接,连续请求多个静态资源
    好比: link标签,发送请求获取css
           script标签,发送请求获取js
           img标签,发送请求获取image图片
复制代码
  1. 浏览器根据html和css造成DOM树和渲染树,绘制到浏览器。
  2. 数据加载完成,断开链接

资源合并与压缩

  1. 合并:减小HTTP请求的数量javascript

  2. 压缩:减小请求资源的大小css

    html压缩:压缩在文本文件中有意义,可是在html中不显示的字符,包括空格,制表符,换行符等, 还有压缩一些其余意义的字符,如HTML注释html

    方式: 
         1. 在线网站压缩
         2. nodejs提供了html-minifier工具
    复制代码

    css压缩: 无效代码删除 css语义合并前端

    方式: 
         1. 使用clean-css对cssj进行压缩
         2. 使用html-minifier对html中的css进行压缩
    复制代码

    js压缩与混乱: 无效字符的剔除: 好比注释回车空格,好比无效的变量 剔除注释 代码语义的缩减和优化: 好比变量名称特别长sommmmesuisan, 压缩为s变量 代码保护: 代码的混乱对前端代码的保护,将代码的风格变的混乱下降可读性vue

    方式: 
         1. 使用uglifyjs2对jsj进行压缩
         2. 使用html-minifier对html中的js代码进行压缩
    复制代码

    文件合并:java

    文件合并的带来的问题:
         1. 首屏渲染问题: 首屏js文件加载过长,好比vue就会出现这样的状况
         2. 缓存失效问题: a17abdh12.js 和b128hsg12h.js两个文件合并后,若是
             a17abdh12.js发生了变化,那么这两个文件合并后的js文件确定也会变化
             。致使用户在访问网站的时候以前缓存的js文件失效。
     
     真实场景:
         1. 通常公共库会合并成一个文件,业务代码会合并为一个文件。公共库修改
             很是少,而业务代码变更的可能性很是高,因此业务代码改动不会影响
             到公共库代码的缓存的失效。
     
     方式: 
         1. 利用nodejs实现文件合并,好比webpack来进行合并
    复制代码

    开启gzip:node

    服务端开启gzip压缩,缩小文件大小,浏览器获取到gzip文件后在解压缩
    复制代码

图片相关

png8/png24/png32之间的区别
    
    1. png8 --- 256色 + 支持透明  + 文件小不少
    2. png24 --- 2^24色 + 不支持透明 + 文件大不少
    3. png32 --- 2^24色 + 支持透明 + 文件最大
    
    备注:每种图片格式都有本身的特色,针对不一样的业务场景选择不一样的图片格式很是重要
    
    不一样格式图片经常使用的业务场景: 
    
    1. jpg有损压缩,文件体积小,不支持透明   ---大部分不须要使用透明图片的场景
    2. png支持透明,浏览器兼容性好     --- 大部分须要使用透明图片的场景
    3. webp压缩体积最小,可是兼容性存在问题   --- ios支持存在问题,安卓尝试使用
    4. svg矢量图,代码内嵌,相对较小,图片样式相对简单的场景  --- 图片样式相对简单的场景
    
复制代码

图片压缩

  1. css雪碧图,整合到一张图片上,减小网站的HTTP请求数量。带来的缺点: 整合图片比较大的时候,一次加载就比较慢了。因此雪碧图也要控制大小webpack

  2. Image inline,将图片的内容内嵌到html当中,减小网站HTTP请求数量, 也就是base64格式的图片,直接写在html中,就不会发送HTTP请求了。ios

  3. 使用矢量图, 使用SVG进行矢量图的绘制,使用iconfont解决icon问题。web

  4. 在安卓下使用webp,图片体积很是很是小,同时具备无损和有损压缩。 在使用webp应该采用降级方式,若是支持使用webp,不然默认仍是使用jpg。

html页面加载渲染的过程

浏览器解析html标签渲染成DOM树,当加载到link标签,会并发的向服务器发送css的资源请求。 当加载到script标签,会向服务器请求js资源,对css进行解析后结合DOM树生成渲染树,接着进行布局,而后绘制。

html渲染过程的特色

  1. 顺序执行, 并发加载

    • 词法分析: 浏览器对html文档解析的方式,从最开始的部分对标签进行从上到下的解析,解析过程从上到下,顺序执行!
    • 并发加载: html引入的外部资源是并发加载的
    • 并发上限: 某个域名下的请求数量是存在上限的,因此对某个域名下所请求资源的数量从而避免达到并发上限
  2. 是否阻塞

    • css阻塞
    1. head标签中阻塞页面渲染
            推荐使用link标签的方式在head中在html中引入
        2. css不阻塞外部脚本js的并发加载,可是会阻塞外部脚本js的执行
            由于js在操做DOM的时候,有可能涉及到css样式的修改,而这个css样式的修改
            是基于以前css样式的渲染。因此在css代码渲染完毕,才会进而执行js代码,
            也就是css代码阻塞了外部js的执行
    复制代码
    • js阻塞
    1. 直接引入的js阻塞页面的渲染,好比<script src='a.js'></script>
            js代码中颇有可能去调用document.write方法来修改DOM文档的结构,
            因此须要等待js代码执行完毕,进而去继续执行html标签的分析,
            因此js脚本代码中不要出现document.write这样的代码
        2. js不阻塞外部资源的加载
        3. js顺序执行,会阻塞后续js逻辑的执行
            举个例子:<script src='a.js'></script>
                      <script src='b.js'></script>
            按照这样的顺序引入,会在a.js里面的代码执行完毕接着执行b.js里面的代码
            由于js的执行是单线程的,也就是b.js里面执行的代码能够依赖a.js中的代码
        
    复制代码
  3. 引入方式

  • js引入方式
1. 直接引入
    2. defer: 确保全部的DOM树都生成
    3. async:不能确保脚本js文件之间的依赖关系,因此async引入的js脚本不能存在依赖关系
    4. 异步动态引入js: 在须要某个js文件的时候,经过生成script标签来引入

复制代码

css和js文件加载过程的优化点

  1. css样式表存放在head中,确保css和html一块儿生成渲染树,而不至于从没有样式,跳转到有样式的状况,出现页面闪动。
  2. 用link标签代替@import这样引入css的方式,@import的方式没法并发加载,另外@import这样的方式会在DOM加载结束后才会加载
  3. js脚本文件放在body底部
  4. 合理使用js的异步加载能力,就是采用动态生成script标签,动态加载所须要的js文件

async 和 defer

  1. async 确保在全部html页面dom渲染完以后才会加载
  2. async 加载的js脚本文件,不是按照顺序加载的,因此只有几个js脚本没有依赖关系,才能够经过async的方式来加载脚本文件
  3. defer 不阻塞页面渲染,是按照顺序执行的,会按照script的顺序依次执行。在DOM渲染完成以后才会执行。

动态引入js脚本

function loadScript(src) {
        let ele = document.createElement('script');
        ele.type = 'text/javascript';
        ele.src = src
        document.body.appendChild(ele)
    }
    loadScript('demo.js')

复制代码

懒加载和预加载

懒加载

  1. 图片进入可视区域以后请求图片资源
  2. 对于电商等图片不少,页面很长的业务场景很是适用
  3. 减小无效资源的加载,由于可能用户只访问100张图片,剩下的100张是没有必要加载出来,这些资源就是属于无效资源。

预加载

  1. 图片等静态资源在使用以前提早请求图片资源
  2. 资源在使用到的时候从缓存中加载,提高用户体验

重绘和回流

回流(reflow): 当render tree中的一部分由于元素尺寸,布局,隐藏等改变而须要从新构建,称为回流。 当页面布局和几何属性改变时就会回流。

触发回流的属性

  1. 盒子模型相关属性
width, height, padding, margin,display,border-width, border,min-height
复制代码
  1. 定位属性
top, bottom, left, right, position, float, clear
复制代码
  1. 改变节点内部文字结构像相关属性
text-align, overflow-y, font-weight, overflow, font-family, line-height
    vertical-align, white-space, font-size
复制代码

重绘:当render tree中一些元素须要更新属性,而这些属性只是影响元素颜色风格,而不影响布局的,好比background-color,color等 称为重绘。

只会触发重绘的属性

color, border-style, border-radius, visibility, text-decoration, background,
    background-size, background-image,background-position, background-repeat,
    outline-color, outline, outline-style, box-shadow
复制代码

重绘不必定会触发回流,可是回流必定会绘制重绘

重绘回流优化方式:

  1. 避免使用触发重绘,回流的CSS属性
  2. 将重绘和回流的范围限制在单独的图层以内(暂时不理解.....)

实际工做中CSS关于回流和重绘的总结

  1. translate 替换top的变化
    translate不会触发回流,top会触发回流

  2. opacity 替换visiblity
    visiblity只会触发重绘的过程,opacity不会触发重绘的过程

    // bad
        setTimeout(() => {
            document.getElementById('box').style.visiblity = 'hidden'
        }, 2000)
        
        // good
        #box {
            width: 100px;
            height: 100px;
            background: red;
            transform: translateZ(0);  // 在浏览器的层面创建一个新图层
            opacity: 1;
        }
        setTimeout(() => {
            document.getElementById('box').style.opacity = 0
        })
    复制代码
  3. 不要一条一条的地修改DOM的样式,预先定义好class,而后修改DOM的ClassName

// bad
    var box = document.getElementId('box')
    setTimeout(() => {
        box.style.width = '200px';  
        box.style.height = '200px';
        box.style.background = 'red'
    })
    
    // good
    .box {
        width: 200px;
        height: 200px;
        background: red;
    }
    setTimeout(() => {
        box.classList.add('box');
    })
复制代码
  1. 把DOM离线后修改(好比,须要频繁操做DOM并将DOM的样式进行修改,那么能够先将DOM的display:none(有一次回流),而后你修改DOM样式100次,在display:block显示出来)
  2. 不要使用table布局,可能很小的小改动会形成整个table的从新布局
  3. 合理选择动画的速度
  4. 当使用实现动画的时候,启用GPU硬件渲染加速,固然若是数据量很大,须要从cpu到gpu的过程也是很是耗费时间的,这个也是须要考量的
.box {
        transform: translateZ(0);
        transform: translate3d(0,0,0);  // 启用GPU硬件加速
    }
```

复制代码
相关文章
相关标签/搜索