美文网首页
前端性能优化及检测工具

前端性能优化及检测工具

作者: 时子释 | 来源:发表于2020-12-20 22:14 被阅读0次

    [TOC]

    chrome性能优化检测工具

    1.谷歌浏览器工具资源管理工具network查看

    • 识别network单个资源的加载过程中的过程和耗时

    • 可以在netword里面将此次与后台交互的资源保存下来,下次可分析或者在别的工具使用

    右键>save all as HAR with content

    1. Lighthouse 选项卡
    • 性能测量工具
    1. show frames per second(FPS) meter
    • 检测网页的fps
    • 打开方式 chrome > 资源管理器 > ctrl+shift+P > 搜索fps
    1. Throttling调整网络吞吐
    • 控制台>network>throttling
    1. 在控制台配置自己的资源监控工具
    • 控制台 > 键入esc 打开自己的工具框
    • more tools > 分别点出 performance monitor,rendering,network request blocking(这个要通过ctrl+shift+P打开)
    • performance monitor 实时监控数据加载,是个很棒的工具
    • network request blocking 可以使匹配到的资源不进行加载,可以用来排除是否必须加载

    性能优化-加载测量指标

    • speed index (加载要少于4s)
    • TTFB
    • 页面加载时间
    • 首次渲染

    性能优化-响应

    • 交互动作反馈时间
    • 帧率FPS
    • 异步请求完成时间

    性能测量模型-RAIL模型

    • response 响应(快)
      处理事件应在50ms内完成
    • animation 动画(流畅)
      10ms一帧
    • idle 空闲(长)
      尽可能增加空闲时间
    • load 加载
      5s内加载完资源

    网站整体测量工具

    1. devtools
    2. lighthouse
    3. webpagetest 自备梯子使用
      webpagetest使用总结

    性能优化方案

    后台开启网络传输的压缩

    • nodejs 使用compression进行资源压缩

    审查页面js的运行耗时长性能问题

    1. 打开控制台的performance标签记录页面的加载和操作的快照
    2. 在时间条页面中找到自己的代码块(在Main程序中一般拉到最下面就是自己的代码块啦),然后查看里面耗时较长的函数看一下有啥问题

    减少重绘回流,页面抖动(layout trashing)

    • 审查方式:通过performance 里的渲染块上是否有红色的三角形标志,来看回流是否是强制的(force reflow),强制的回流会引起页面抖动
    • 问题成因:批量读写不分离,会引起强制回流。
    cord.style.width = cards.offsetTop+1+'px'; // cards.offsetTop引起读取高度触发回流,再赋予高度又触发回流,连续的读写触发强制更新,引起页面抖动
    

    以下会引起回流

    1. 改变窗口大小
    2. font-size大小改变
    3. 增加或者移除样式表
    4. 内容变化(input中输入文字会导致)
    5. 激活CSS伪类(:hover)
    6. 操作class属性,新增或者减少
    7. js操作dom
    8. offset相关属性读取和计算
    9. 设置style的值 ......
    • 解决方案:日常读写分离/使用fast-dom插件

    fast-dom使用API

    // 实现
     fastdom.measure(()=>{
         let top =  cards.offsetTop+1+'px';
         fastdom.mutate(()=>{
             cord.style.width = top; 
         })
     })
    

    减少布局和重绘(repaint)

    • 如何识别paint的瓶颈-如何查看重绘
    • 减少图层的消耗-使用transform和 opacity
    • 使用willchange使动画提取到单独的图层里
    willchange: transform;
    
    • 使用raf进行动画-解决页面卡顿,抖动问题

    缩短js的解析开销

    • 开销
      1. 加载
      2. 执行
      3. 解析&编译
    • 加载解决方案
      1. code splitting 代码拆分,按需加载
      2. tree shaking 代码减重
    • 执行解决方案
      1. 避免长任务
      2. 避免超过1kb的行间脚本
      3. 使用rAF和rIdC进行时间调度
    • 解析&编译解决方案
      • 函数优化
        1. 懒解析 lazy parsing VS 饥饿解析 eager parsing
        // 通过括号来触发饥饿解析,饥饿解析就是立即解析,页面加载的时候就立即解析,这样再运行时会减少解析时间,却会增多加载页面的时间,有利有弊;
        var sum = (a,b)=>a+b; // 正常解析-懒解析
        var sum = ((a,b)=>a+b); // 饥饿解析,
        
        1. 利用Optimize.js优化初次加载的时间
          压缩文件插件会去掉触发饥饿解析的括号,Optimise.js可帮忙找回
      • 对象优化
        1. 以相同顺序初始化对象成员,避免隐藏类的调整
            var a = {color:'blue'} // HC0-隐藏类
            a.seat = 4; // HC1
            
            var a2 = {seat:4}, // 重新创建HC0,无法复用上面的隐藏类对象 
            a2.color = 'red'; // HC1
            
            var a3 = {color:'blue'} // 沿用HC0
            a.seat = 4; // 沿用HC1
        
        1. 实例化后避免添加新属性
        var a = {color:'blue'} // In-object 属性 
            a.seat = 4; // normal/fast属性,存储property store属性里,需要通过描数组简介查找
        
        1. 尽量使用Array代替array-like对象
        2. 避免读取超过数组的长度-越界的时候会返回undefind,当循环中有对数组元素进行比较时,会导致沿着原型链向上查找,增加额外的开销
        3. 避免元素类型转换

          元素类型有隐藏的自降级优化体系
        // 对数组的数据类型转化而采取的优化策略,越往后开销越大。holey是数据删除后留下的坑的意思
          packed_smi_elements->packed_double_elements->packed_elements
          |                     |                       | 
          holey_smi_elements -> holey_double_elements-> holey_elements
        

    html优化-html-minifier插件

    • 减少iframes的使用,iframes资源下载会占用父级的资源下载,解析进程,可以在父窗口load后再加
    • 压缩空白符
    • 避免节点深层次嵌套,子级越多,生成dom树消耗(遍历dom树节点)越多
    • 避免使用table布局
    • 删除注释
    • css&js尽量外链
    • 删除元素默认属性

    css优化

    • devtools查看css性能开销

      performance录制 > Main里面的recalculate Style块
    • 降低css对渲染的阻塞(较少代码块大小)
    • 利用GPU进行完成动画
    • 使用contain属性

    contain 属性的主要目的是隔离指定内容的样式、布局和渲染。开发人员可以使用这个 contain 属性来限制指定的DOM元素和它的子元素同页面上其它内容的联系;我们可以把它看做一个iframe。跟iframe很相似,它能建立起一个边界,产生一个新的根布局;保证了它和它的子元素的DOM变化不会触发父元素重新布局、渲染等。

    .a li {
        padding:10px;
        contain:layout;
    }
    
    • font-display属性

    资源压缩与合并

    • html压缩
      1. 使用在线工具压缩
      2. 使用html-minifier等npm工具
    • css压缩
      1. 使用在线工具压缩
      2. 使用clean-css等工具
    • js压缩与混淆
      1. 使用在线工具压缩
      2. 使用webpack
    • js或css文件是否合并
      1. 若干小文件,也许可以
      2. 无冲突,服务相同的模块,可以
      3. 优化加载,不考虑

    图片优化

    • 图片压缩
      1. imagemin,也有github
      2. imagemin-pngquant
    • 图片懒加载-插件很多不列举
    • 使用渐进式图片
      1. baseline JPEG行扫描图片,图片加载显示是一行一行的,体验不是很好
      2. Progressive JPEG 从低像素到高像素加载
      3. 美工可以制作渐进式图片或者下面的工具自己转

        progressive-imge ImageMegick libjpeg jpegtran jpeg-recompress imagemin
    • 使用响应式图片
      1. srcset属性,设置多尺寸图
      2. sizes属性,识别边界
      // 其中srcset指定图片的地址和对应的图片质量。sizes用来设置图片的尺寸零界点
      <img srcset="a.png 100w,a.png 200w" sizes="100vw">
      
      1. picture新属性

    字体优化

    • 文字因为下载,闪烁不可避免
    • 使用font-display规避闪烁效果
    font-display:block; // 阻塞3s不显示,直到下载完成显示
    font-display:swap; // 先用默认字体,然后字体下载完成再更换
    font-display:optional; // 移动端解决方案, 加载下载字体,如果一定时间后显示不出来替换成系统字体,不再改变成加载字体
    

    babel7优化配置

    • 在需要的地方引入polyfill
      babel 添加垫片polyfill配置在babel.config.js里可配置,减少打包不需要的垫片代码
        "useBuiltIns":"usage"
    
    • 辅助函数按需引入
    • 根据目标浏览器按需转换代码
      babel.config.js里可配置
        "targets":{
            "browsers":[">0.25%"] //这个百分比是保留浏览器兼容版本列表
        }
    

    webpack配置

    • 忽略某些库 noParse
    // webpack.config.js
    module:{
        noParse:/lodash/, //忽略lodash库,不进行递归解析
    }
    
    
    • 避免打包的时候对不变的库重复构建,提高构建速度-DllPlugin
    • 基于webpack的代码拆分
      1. 把单个bundle文件拆分成若干小bundles/chunks-缩短首屏加载时间
      2. splitChunks提取公有代码,拆分业务代码与第三方库
    optimization:{
        splitChunks:{
            cacheGrounps:{
                vendor: {
                    name:'vendor',
                    test:/[\\/]node_module[\\/]/,
                    minSize:0,
                    minChunks:1,
                    priority:10,
                    chunks:'initial'
                },
                common:{
                    name:'common',
                    test:/[\\/]src[\\/]/,
                    chunks:'all',
                    minSize:0,
                    minChunks:2,
                    
                }
            }
        }
    }
    
    1. 动态加载
    // 常规加载
    import {add} from './math'
    console.log(add(1,2)
    
    // 动态加载
    import('./math').then(math=>{
        console.log(math.add(1,2))
    })
    
    • 基于webpack 的代码压缩mimification
      1. terser-js代码压缩
      2. mini-css-extract-plugin+optimizeCssAssetsPlugin压缩css
      3. htmlwebpackpackplugin-minify压缩html

    持久化缓存方案

    • 每个打包的资源文件有唯一的hash值
    • 修改后只有受影响的文件hash变化
    • 充分利用浏览器缓存

    webpack打包监测和分析的工具

    • stats分析和可视化图
      1. webpack-charts
    • webpack-bundle-analyzer 进行体积分析
    • speed-measurt-webpack-plugin 速度测试
    • 也可以用官方的

    启用Gzip压缩

    • 对资源传输进行压缩可达90%
    • 用ngnix
    • 服务器自己加

    启用keep alive

    • 建立tcp连接在initial connection里面
    • 启用keep alive后只有第一个连接有initial connection消耗,其他连接都没有了
    • keep alive 能保持连接,无需重新重新建立连接
    • keep alive 默认自己启用 在response headers里的connection可见

    http缓存

    Service Workers作用

    • 加速重复访问
    • 离线支持

    http2

    • 二进制传输
    • 请求响应多路复用
    • Server push
    • 如何访问不安全的网站,在浏览器报不安全界面,直接输入thisisunsafe并且回车,即可直接访问
    • 适用于请求量高的网站
    • 具体ngnix配置百度即可

    SSR服务端渲染

    • 加速首屏加载
    • 更好的SEO

    PS

    PerformanceNavigationTiming 浏览器接口

    // 获取时间接口
    // 在load事件后触发
    window.addEventListener('load',(event)=>{
        // 获取可交互时间
        let timing = performance.getEntriesByType('navigation')[0];
        let tti = timing.domInteractive - timing.fetchStart;
        console.log("TTI:"+tti);
    })
    
    • DNS 解析耗时: domainLookupEnd - domainLookupStart
    • TCP 连接耗时: connectEnd - connectStart
    • SSL 安全连接耗时: connectEnd - secureConnectionStart
    • 网络请求耗时 (TTFB): responseStart - requestStart
    • 数据传输耗时: responseEnd - responseStart
    • DOM 解析耗时: domInteractive - responseEnd
    • 资源加载耗时: loadEventStart - domContentLoadedEventEnd
    • First Byte时间: responseStart - domainLookupStart
    • 白屏时间: responseEnd - fetchStart
    • 首次可交互时间: domInteractive - fetchStart
    • DOM Ready 时间: domContentLoadEventEnd - fetchStart
    • 页面完全加载时间: loadEventStart - fetchStart
    • http 头部大小: transferSize - encodedBodySize
    • 重定向次数:performance.navigation.redirectCount
    • 重定向耗时: redirectEnd - redirectStart
    navigationStart 加载起始时间
    redirectStart 重定向开始时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回开始重定向的fetchStart的值。其他情况,则返回0)
    redirectEnd 重定向结束时间(如果发生了HTTP重定向,每次重定向都和当前文档同域的话,就返回最后一次重定向接受完数据的时间。其他情况则返回0)
    fetchStart 浏览器发起资源请求时,如果有缓存,则返回读取缓存的开始时间
    domainLookupStart 查询DNS的开始时间。如果请求没有发起DNS请求,如keep-alive,缓存等,则返回fetchStart
    domainLookupEnd 查询DNS的结束时间。如果没有发起DNS请求,同上
    connectStart 开始建立TCP请求的时间。如果请求是keep-alive,缓存等,则返回domainLookupEnd
    (secureConnectionStart) 如果在进行TLS或SSL,则返回握手时间
    connectEnd 完成TCP链接的时间。如果是keep-alive,缓存等,同connectStart
    requestStart 发起请求的时间
    responseStart 服务器开始响应的时间
    domLoading 从图中看是开始渲染dom的时间,具体未知
    domInteractive 未知
    domContentLoadedEventStart 开始触发DomContentLoadedEvent事件的时间
    domContentLoadedEventEnd DomContentLoadedEvent事件结束的时间
    domComplete 从图中看是dom渲染完成时间,具体未知
    loadEventStart 触发load的时间,如没有则返回0
    loadEventEnd load事件执行完的时间,如没有则返回0
    unloadEventStart unload事件触发的时间
    unloadEventEnd unload事件执行完的时间
    

    检查页面中所有的长任务

    let observer = new PerformanceObserver((list)=>{
        for(const entry of list.getEntries()){
        console.log(entry)
    }}) 
    observer.observe({entryTypes:['longtask']});
    

    检查页面是否可见

    这是只有浏览器的行为会触发,如切换页签和最小化

    let vEvent = 'visibilitychange';
    if(document.webkitHidden != undefined){
        // webkit事件名称
        vEvent = 'webkitvisibilitychange';
    }
    function visibilityChanged(){
        if(document.hidden || document.webkitHidden){
            console.log("Web page is hidden");
        } else { // 页面可见
            console.log("Web page is visibile");
        }
    }
    document.addEventListener(vEvent, visibilityChanged,false);
    

    检测网络变化状况

    如果网络发生变化,就要加载不同大小的资源来保证网站打开速度流畅

    let connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
    let type = connection.effectiveType;
    function updateConnectionStatus() {
       console.log("connection type change from " + type + " to " + connection.effectiveType);
    }
    connection.addEventListener('change',updateConnectionStatus,false);
    

    浏览器的绘制过程

    这里说的是重新计算布局,也就是当使用css或者js进行动画或者crud dom节点时候的过程

    js/css > style > layout > paint > composite

    • js/css 重新设计页面元素的驱动者
    • style 重新计算关联元素的颜色,字体这些
    • layout 布局计算每个节点精确的位置和大小-“盒模型”
    • paint 绘制是像素化每个节点的过程
    • composite 复合图层
      • 复合线程
      1. 将页面拆分图层进行绘制再进行复合
      2. 如何再浏览器控制台查看图层

        老版本谷歌:
        performance > 点击frames中要查看的某一块>下面选项卡的layer>显示出的列表就是每一个图层啦
        新版本谷歌(和performance同级的选项卡,勾出来即可):
        控制台汉堡包选项(竖向三个点) > more tools> layers
      3. 如何查看重绘
        <span id="如何查看重绘"></span>
        performance > 键入esc > 下方选项卡勾选出rendering > 勾选 Paint Flashing
        重绘的元素会以绿色显示

    v8引擎工作原理

    1. 源码的编译过程 => 抽象语法树 > 字节码bytecode > 机器码
    2. 编译过程会进行优化
    3. 运行时可能发生反优化

      第二,三点,比如数据类型的编译,如果再js代码中循环对一个数组进行函数数字运算,编译过程会将它优化成只有数据类型,不进行类型检测,运行速度会快许多,当参与运算的数组中放入一个字符串的时候,编译过程无法优化,需要每次迭代都进行参数类型验证,运行速度明显下降。
    4. V8优化机制
      • 脚本流 (边下载边解析,比如当一个脚本超过30kb,认为足够大,就单独开一个线程进行解析,不用等所有都下载完成)
      • 字节码缓存 (使用频率高的字节码片段会临时存储,等下次运行从缓存中使用)
      • 懒解析 (函数声明,但是不解析里面的逻辑,等运行时再解析)<i id="懒解析"></i>
    5. tree-shaking
    • 上下文未用到的代码(dead code)
    • 基于ES6 import export
    • package.json中配置sideEffects
    • 注意Babel默认配置影响

    如有问题烦请评论告知,如有喜欢请点个赞哈哈哈

    相关文章

      网友评论

          本文标题:前端性能优化及检测工具

          本文链接:https://www.haomeiwen.com/subject/rlklnktx.html