公司的技术课程,还挺全面的,从网络传输,缓存配置,静态资源加载,运行时优化四个方面进行了阐述,做了个小笔记

网络传输

  1. 开启HTTP2

    • 🔥多路复用,多个请求复用一个TCP连接
    • 二进制传输,解析高效,体积小
    • 消息头压缩,压缩Header体积,建立字典,用索引号表示重复的字符串
    • 服务端push(一般不用,可以用preload替代
  2. CDN部署静态资源

    • 用户先向edge发请求,如果edge找不到,再往上级找,直到请求到root
    • 找到资源时,同时在各个edge上缓存该资源
    • 所以资源直接上传到root
    • 冷启动问题:使用预热
    • CDN不过期问题:
      • 配置较短的过期时间,或者手动刷新CDN
      • 与客户端缓存配合:CDN节点缓存等于客户端强缓存的时间
  3. DNS预解析 dns-prefetch:针对一些小众网站,dns解析可能会长达0.5秒

  4. 提前建立网络连接 preconnect:提前做好DNS,TCP,SSL的过程,到时直接传数据即可

  5. 域名收敛:把静态资源部署到尽可能少的域名下

    • 充分发挥HTTP2的多路复用特性

    • 最大化节省DNS解析,TCP建连等网络成本

      之前提倡域名发散,是因为HTTP1.1时代,浏览器对同域名请求有并发限制

  6. 使用brotil压缩:优于gzip压缩

  7. 优化https:多次握手,TLS相关算法会造成额外开销,导致相比http性能差距大【有点硬核,略过】

使用缓存

  1. DNS缓存:
    • 解析路径:浏览器缓存 → 操作系统缓存 → DNS缓存
  2. 宿主浏览器缓存,以优先级排序
    • memory缓存:优先级最高,不是所有资源都能memory缓存,如js
    • cache API缓存:如PWA
    • http缓存:强缓存,协商缓存
    • push缓存:HTTP2的Server push开启时才有的缓存,略过
  3. 运行时缓存:与业务耦合较重,需要因地制宜优化
    • Cookie:存放简单数据
    • LocalStorage:存储一定体积的数据
    • IndexDB:存放大量结构化的数据
    • Memory:存放临时数据

静态资源加载

  1. 资源预加载

    • 预加载当前页面资源 link preload
    • 预加载下级页面的资源 link prefetch :空闲时才会做fetch
    • 直接渲染好二级页面: link prerender:性能损耗大
  2. HTML加载

    • 控制HTML体积
      1. 传输体积不要超过30kb
      2. 减少DOM节点和属性
      3. 谨慎使用内联
    • 骨架屏
  3. JS加载

    • 优化加载方式

      1. 传统JS加载:同步执行,阻塞DOM生成
      2. defer加载:立即下载资源,DOM生成完之后才会执行
      3. async加载:立即下载资源,异步执行,不阻塞DOM
      4. type="module":支持ES Module的同时自带了defer的特性
      5. type="module" async :支持ES Module的同时自带了async的特性

      生产环境不建议使用 type=”module”,一是因为兼容性不好,二是因为串行加载,限制了速度,开发环境下配合vite,snowpack不错

    • 优化文件体积

      1. 压缩:terser压缩文本代码,gzip二进制压缩
      2. 按需加载,code splitting,把不重要的代码单独拆分出来,需要了再去加载(dynamic import
      3. 精准控制polyfill:通过browsrelist申明宿主环境,只注入需要的polyfill
      4. Tree Shaking:只有ES Module才可以,同时需要对副作用进行申明
      5. 谨慎引入三方库
    • 优化网络请求

      1. 动静分离打包:

        • 动:经常改动的业务,UI代码
        • 静:common的公共库,很少进行改动
        • 目的:充分利用HTTP缓存,对于静的资源,用户没有二次下载成本
      2. 主次分割:

        • 主要模块 major:可以特指首屏依赖的模块,需要最高优先级处理,保证体积和逻辑尽可能少,首先加载,获得最有体验

        • 次要模块 minor:指非首屏区域的内容,允许这部分出现的稍晚和页面闪烁

      3. 优化网络请求-尽可能利用缓存

      • 文件指纹:利用hash来生成文件名,进行版本控制
      • 缓存时长控制
  4. CSS加载

    • 合理选择加载方式
      1. 内联加载:很快,但是造成HTML体积增大,且HTML缓存时间较短
      2. link标签引入
      3. CSS in JS:JS动态注入样式,用于业务强相关的需求
    • 优化文件体积
      1. 压缩:使用cssnano + gzip
      2. 精准控制prefix:同样通过browserlist
      3. 去除冗余样式:使用PurifyCSS或CSS Module
    • CSS加载:与JS类似,动静分离与主次分割
    • 优化网络请求:与JS一致
  5. 图片加载

    • 控制加载时机
      • 关键图片:大图片使用 preload 预加载,小图片使用base64内联
      • 次要图片:可以选择懒加载
    • 图片格式:
      • 矢量图:svg
      • 像素图:能webp就webp,不能则
        • 颜色少,层次分明:png
        • 颜色,渐变多,复杂:jpg
    • 不同设备加载不同size:媒体查询和 picture标签
    • 如果关键大图体积较大,可以拆分成一个核心图和多个边缘小图
  6. 字体加载

    • 控制加载时机:与JS,CSS相似
    • 控制加载策略
      • 关键字体配置为 font-display: block,意思是等到字体下载完才渲染
      • 次要字体配置为 font-display: swap,意思是先用默认字体渲染,字体下载完再进行替换
    • 字体格式选择:PC使用 woff,移动端使用 ttf
    • 字体裁剪:
      • 使用工具裁剪,生成子集,如 fontmin,subfont(只适用于静态文本
      • 生成字体时,只引入我们需要的font-weight
      • 缓存策略:与JS,CSS相似

运行时优化

  1. HTML
    • 减少DOM元素数量
    • 使用 innerHTML 来增删多个元素
    • 使用 getElementByXX 来选择元素
  2. JS
    • 网络请求提前:与首屏渲染强相关的请求,可以提前发起,放到JS第一行,或者提前到HTML中发起
    • 避免出现CPU高占用
      • 合理处理long task,task拆分,异步执行,复用结果,使用 web worker等
      • 减少触发频率:防抖,节流
      • JS动画使用 requestAnimationFrame 而不是 setInterval
    • 合理使用内存
      • 避免内存泄漏:
        • 全局变量无法被GC
        • 对DOM始终存在引用
        • 闭包引用自由变量
      • 使用事件委托:绑定相同事件到多个DOM上时,可以绑定到父元素上,通过事件冒泡来处理
      • 使用缓存:JS内部缓存和宿主缓存(参考第二章
  3. CSS
    • 不使用 @import:会导致额外的加载时间
    • 使用现代布局方案:flex和grid
    • 避免高频触发重绘,重排
      • 绝对定位
      • 提前标明元素的宽高,避免后续的重排
    • 优先使用CSS实现动画


经验分享      前端

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!