美文网首页
性能优化探索

性能优化探索

作者: halowyn | 来源:发表于2021-03-15 17:29 被阅读0次

    性能优化指标

    • 加载指标
      • speedIndex速度指数:代表页面内容渲染所消耗的时间
      • TTFB:是 Time to First Byte 的缩写,指的是浏览器开始收到服务器响应数据的时间(后台处理时间+重定向时间),是反映服务端响应速度的重要指标,TTFB 时间如果超过了 500 ms,用户在打开网页的时候就会感觉到明显的等待
      • 页面加载时间
      • 首次渲染: 渐进式加载
    • 响应指标
      • 交互动作的反馈时间
      • 帧率FPS :是指画面每秒传输[帧数],通俗来讲就是指动画或视频的画面数,每秒钟帧数越多,所显示的动作就会越流畅
      • 异步请求的完成时间

    RAIL测量模型(量化性能优化指标/RAIL评估标准)

    1. Response 响应:处理事件应在50ms以内完成,这样给用户的感受是瞬间就完成了

      • 事件处理函数在50ms内完成,考虑到idle task的情况,事件会排队,等待时间大概在50ms。适用于click,toggle,starting animations等,不适用于drag和scroll。
      • 复杂的js计算尽可能放在后台,如web worker,避免对用户输入造成阻塞
      • 超过50ms的响应,一定要提供反馈,比如倒计时,进度百分比等。
    2. Animation 动画:每10ms产生一帧

      • 在一些高压点上,比如动画,不要去挑战cpu,尽可能地少做事,如:取offset,设置style等操作。尽可能地保证60帧的体验。
      • 在渲染性能上,针对不同的动画做一些特定优化
    3. Idle 空闲:尽可能增加空闲时间

      • 用空闲时间来完成一些延后的工作,如先加载页面可见的部分,然后利用空闲时间加载剩余部分,此处可以使用 requestIdleCallback API
      • 在空闲时间内执行的任务尽量控制在50ms以内,如果更长的话,会影响input handle的pending时间
      • 如果用户在空闲时间任务进行时进行交互,必须以此为最高优先级,并暂停空闲时间的任务
    4. Load 加载:在5s内完成内容的加载并可以交互

    分析RAIL用的性能测量工具

    1. chrome DevTools开发调试、性能评测
      audit Lighthouse
      throttling 调整网络吞吐量
      performance
      network

    2. Lighthouse网站整体质量评估,也可以直接使用chrome DevTools中的lighthouse

          npm i -g lighthouse
          lighthouse http://www.bilibili.com
      
    1. WebpageTest多测试地点、全面性能报告解读
      • waterfall chart请求瀑布图
      • first view 首次访问
      • repeat view 二次访问(反映缓存的优化情况)
      • WebpageTest在线配置
      • 本地配置WebpageTest(安装docker)

    性能优化策略

    一、渲染优化


    1. 关键渲染路径:

      • javascript(触发视觉变化)
      • style计算样式
      • layout布局
      • paint绘制
      • composite复合
    2. 影响回流的操作 reflow

      1. 添加/删除元素
      2. 操作styles
      3. display: none
      4. offsetLeft, scrollTop, clientWidth
      5. 移动元素位置
      6. 修改浏览器大小,字体
    3. 避免布局抖动(layout thrashing )

      1. 避免回流
        • transform/translate进行复合
      2. 读写分离
        • 解决方案FastDom
        • measure和mutate方法的使用
    4. 复合线程(compositor thread)与图层(layer)
      将页面拆分图层进行绘制再进行复合
      利用DevTools了解网页的图层拆分情况
      哪些样式仅影响复合

    5. 减少重绘的方案
      利用devTools发现paint的瓶颈
      will-change创建新的图层

    6. 高频事件处理函数 防抖 (requestAnimationFrame)

    二、 代码优化


    1. code splitting代码拆分,按需加载
    2. tree shaking 代码减重
    3. 减少主线程工作量
      避免长任务
      避免超过1kb的行间脚本
      使用rAF和rIC进行实践调度
    • V8优化机制(js代码优化原理)
      • 脚本流
      • 字节码缓存
      • 懒解析
    1. 函数优化

    2. 函数解析方式

      • lazy parsing VS eager parsing
      • 利用optimize.js优化初次加载时间
      • 直接使用uglify.js优化
    3. 对象优化

      • 以相同顺序初始化对象成员,避免隐藏类的调整
      • 实例化后避免添加新属性
      • 尽量使用Array代替array-like对象
      // bad
      Array.prototype.forEach.call(arrObj, (value, index) => {
          console.log(`${index}:${value}`)
      })
      
      // good
      const arr = Array.prototype.slice.call(arrObj, 0)
      arr.prototype.forEach.call(arrObj, (value, index) => {
          console.log(`${index}: finger ${value}`)
      })
      
      • 避免读取超过数组的长度
      functon foo (arr) {
          for(let i = 0; i <= arr.length; i++) { // 越界
              if (arr[i] > 1000) { // 1. 造成undefined跟数组进行比较 2.造成沿原型链的额外查找
              console.log(arr[i])}
          }
      }
      // 10, 100, 1000[]
      
      • 避免元素类型转换
      const arr = [3, 2, 1] // PACKED_SMI_ELEMENTS
      arr.push(4.4) // PACKED_DOUBLE_ELEMENTS 优化降级
      

    三、HTML优化


    1. 减少iframes的使用(可以延迟加载)

      <iframe id='a'></iframe>
      document.getElementById('a').setAttribute('src', 'url')
      
    2. 压缩空白符

    3. 避免节点深层级嵌套

    4. 避免使用table布局

    5. 删除注释

    6. CSS&Javascript尽量外链

    7. 删除元素的默认属性

    • 借助工具
      html-minifier

    四、 CSS优化


    自右向左过滤样式

    1. 降低css对渲染的阻塞
    2. 利用GPU进行完成动画
    3. 使用contain: layout(对元素单独处理不会影响其他元素)
    4. 使用font-display属性

    五、 资源的压缩与合并


    1. 减少http请求数量
    2. 减少请求资源本身的大小

    HTML压缩

    • 使用在线工具进行压缩
    • 使用html-minifier等npm压缩工具

    CSS压缩

    • 使用在线工具进行压缩
    • 使用clean-css等npm工具

    JS压缩与混淆

    • 使用在线工具进行压缩
    • 使用webpack对js在构建时压缩

    CSS JS文件合并

    • 若干小文件
    • 无冲突,服务相同的模块ok
    • 优化加载NO

    六、 图片优化方案


    1. 图片JPG/JPEG(压缩比高)
      • 工具imagemin
      • 使用场景:保证画质和色彩
      • 缺陷:纹理和边缘比较粗糙
    2. png
      • 体积比较大,适合图标和logo
      • imagemin-pngquant
    3. webP
    4. svg

    图片加载优化

    1.懒加载

    * 原生图片懒加载
    * 第三方图片懒加载方案(verlok/lazyload、yall.js\Blazy)
    

    2.渐进式图片(清晰度由低到高)

    * progressive-image
    * imageMagick
    * libjpeg
    * jpegtran
    * jpeg-recompress
    * imagemin
    
    1. 响应式图片

      • srcset属性的使用(提供多个尺寸下对应的图片)
      • sizes属性的使用()
      • picture的使用

    字体优化

    • @font-face
    • font-display: auto/block/swap/fallback/optional
    • ajax+base64:解决了兼容性问题

    七、webpack优化


    1. tree-shaking
      • 上下文未用到的代码
      • 基于es6 import export
      • 全局作用于sideEffects: ['*.css']
      • 注意babel默认配置的影响
    2. js压缩
      • webpack4后引入uglifyjs-webpack-plugin
      • 支持es6替换为terser-webpack-plugin
      • 减小js文件体积
    3. 作用域提升
    4. babel7优化配置
      • 在需要的地方引入polyfill, useBultIns: usage
      • 辅助函数的按需引入
      • 根据目标浏览器按需转换代码

    webpack依赖优化

    1. noParse

      • 提高构建速度
      • 直接通知webpack忽略较大的库
      • 被忽略的库不能用import、require、define的引入方式
    2. dllPlugin(主要用在开发环境打包)

      • 避免打包时对不变的库重复构建
      • 提高构建速度

    基于webpack的代码拆分

    把单个bundle文件拆分成多个小的bundle/chunk
    提高首屏加载速度

    1. 手工定义人口
    2. 动态加载改造
    3. split-chunks提取共有代码,拆分业务代码与第三方库
    optimizaton: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    name: 'vendor',
                    test: [匹配node_modules],
                    minsize: 0,
                    minChunks: 1, // 最少段数
                    priority: 10, // 拆分优先级
                    chunks: 'initial'
                }
            } 
        }
    },
    common: {
        name:'common',
        test: [匹配src],
        chunks: 'all'
        minsize: 0,
        minChunks: 1 // 最少段数
    }
    

    基于webpack的资源压缩(minification)

    1. terser压缩js
    2. mini-css-extract-plugin 压缩css
    3. HtmlWebpackPlugin-minify压缩HTML

    基于webpack的资源持久化缓存

    1. 每个打败的资源文件有唯一的hash值
    2. 修改后只有受影响的文件hash变化
    3. 充分利用浏览器缓存
    output: {
        path: `${__dirname}/build`,
        filename: '[name].[hash].bundle.js'
        chunkFilename: '[name].[chunkhash:8].bundle.js'
    }
    

    基于webpack应用的监测与分析

    1. stats分析与可视化图,webpack chart

      webpack --profile --json >stats.json
      
    2. webpack-bundle-analyzer进行体积分析

      source-map-explorer(基于sourcemap生成)

    3. speed-measure-webpack-plugin速度分析

    react按需加载

    1. React router基于webpack动态引入
    2. 使用reloadable高级组件

    八、传输加载优化

    1. nginx配置启用压缩gzip, 对传输资源进行提及压缩,可高达90%
        gzip on
        gzip_min_length 1k // 最小文件
        gzip_comp_level 6 // 压缩级别
        gzip_types text/plain applicaton/javascript text/css text/javascript
    
    1. http启用Keep Alive
      • 一个持久的TCP连接,节省了连接创建时间
      • 基于nginx的配置默认开启
    # keepalive_timeout 0 // 不开启
    keepalive_timeout 65 // 开启
    keepalive_requests 100 // 利用这个tcp链接可以发起的请求上限
    
    1. http缓存
      • 提高重复访问时资源加载的速度
      • 强缓存和协商缓存
        协商缓存ETag和if-no-match
        cache-control/expires
        last-modify/if-modify-since


        image.png
    2. service workers作用
      • 加速重复访问
      • 离线支持
        注意
      • 延长了首屏时间,但页面总加载时间减少
      • 兼容性
      • 只能在localhost或https下使用
    3. http/2的提升
      • 二进制传输(提高传输效率,对头部进行压缩)

      • 请求响应多路复用
        nginx配置http2


        image.png image.png image.png
        配置自己生成签名的证书
        image.png
        - 重启nginx
        • https形式的localhost
        • thisisunsafe
        • nginx配置http2
      • server push 服务器推送

        image.png image.png
    • 只能工作在https下
    • 适合较高的请求量
    1. 服务端渲染
      • 首屏渲染优化
      • 利于seo
      • react react-dom next(服务端渲染插件)

    九、前沿优化解决方案

    1. 拯救移动端图片-svg
      1. 从png到iconfont
        • 多个图标一套字体,减少获取的请求数量和体积
        • 矢量图形可伸缩
        • 可以通过css修改大小和颜色
      2. 从iconfont到svg
        • 保存了图片能力,支持多色彩
        • 独立的矢量图形
        • xml语法,搜索引擎seo和无障碍读屏软件读取
    2. 使用flexbox优化布局
      • 更高性能的实现方案(相对于float:render和paint的时间更短)
      • 容器有能力决定自元素的大小、顺序、对齐、间隔等
      • 双向布局
    3. 优化资源加载顺序
      • 浏览器默认安排资源加载优先级(html解析)
      • 使用preload、prefetch调整优先级
        • preload:提前加载较晚出现,但对当前页面比较重要的资源
        • prefetch:提前加载后续路由需要的资源,优先级低
        • webpack中也可以设置preload/prefetch
    4. 预渲染页面
      • react-snap
        • (配置postbuild)
        • 使用ReactDom-hydrate
        • 内敛样式,避免明显的FOUC(样式闪动)
      • 大型单页应用的性能瓶颈:js下载+解析+执行
      • ssr的主要问题:牺牲TTFB来补救Firdt Paint;实现复杂
      • Pre-rendering打包时提前渲染页面,没有服务端参与
    5. windowing(窗口化)提高列表性能
      • 加载大列表、大表单严重影响性能
      • lazy loading仍然会让DOM变得过大
      • windowing只渲染可建行,渲染和滚动的性能都会提升
        react-window:可避免因为数据的更新而导致大量的重新渲染。
        • 配置一个一位列表List
        • 配置一个二维列表Grid
        • 配置滚动到指定元素
    6. 使用骨架组件减少布局移动(Layout Shift)
      • skeleton/Placeholder 的作用
        • 占位
        • 提升用户感知性能
        • react-placeholder


          image.png

    相关文章

      网友评论

          本文标题:性能优化探索

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