前端性能优化

思考:

从A页面 到B页面,会经历哪些步骤?

  •   离开A页面
  •   路由重定向,指向B页面
  •   webworker 主从线程 master and slave MS线程 init
  •   网络初始化 http socket等
  •   页面layout tree,节点组装+样式+逻辑对节点的改变  重排
  •   processing 重绘和对layout-tree的一些逻辑处理

跳转特别慢,如何优化?

  首先需要知道到底是哪一步特别慢,可以利用浏览器提供的钩子埋点,检测每个步骤的耗时:

chrome提供的performance

navigation timing API  - 测量页面加载速度,采集每一个步骤所需时间

常用API如下:

  • 1. navigationStart
    • 上一个页面卸载结束时触发,如果新页进入就相当于 fetchStart
  • 2. unloadEventStart /end
    •   标识前一个网页unload的点,新页进入,这个值为0
  • 3. redirectStart / end
    •   标识一个重定向的持续时间
  • 4. fetchStart /end
    •   浏览器准备好使用http请求抓取文档的时间,文件打包大小之类的优化
  • 5. domainLockupStart /end
    •   页面请求http(包含TCP)开始和重新建立连接的时间,把一些请求后置减少这段时间,逻辑线程会block渲染线程
  • 6. connectStart / end
    •   网络请求建立和持续的时间,持久连接的话 相当于 fetchStart
  • 7. secureConnectionStart / end
    •   https连接所用时间,衡量http和https时间差
  • 8. requestStart /end
    •   连接请求的时间 包含 from cache,从缓存中读取数据
  • 9. responseStart / end
    •   返回持续时间  包含 from cache
  • 10. domLoading
    •   开始解析渲染dom树  dom的 readyState,当dom渲染时这个值变成loading时 会抛出readystatechange readyState发生变化
  • 11. domInteractive
    •   dom树解析完成  readyState 值变为 interactive 也会触发readystatechange
  • 12. domCotentLoadedEvebtStart / end
    •   网页资源加载时间 js脚本之类的
  • 13. domComplete
    •   逻辑执行完毕,资源就绪,dom树解析完成的点
  • 14. loadEventStart / end
    •   load事件回调的时间

在这些地方埋点 就可以采集每个阶段所用时间,定位需要优化的点,比如可以人为计算一些时间,设置一些阈值,超过一定阈值之后做一些操作,比如邮件警告,办公软件提示等。

代码中可以用 window.performance.timing 来获取时间:

  javascript: (() => {
    const perfData = window.performance.timing;
    const pageLoadTime = perfData.loadEventEnd - perfData.navigationstart;
    console.log("页面加载耗时:",pageLoadTime,'ms');
  })();

如何评定加载速度是否合适?衡量标准是什么呢?

Core Web vitals - 网页核心的性能指标

* Google提出的衡量标准,每个CWN代表用户体验的一个不同方面

大致从加载速度 | 交互友好 | 稳定性三个方向,将加载速度描述为可衡量的,并反映真实体验:

1. 衡量加载速度 Largest Contentful Paint(LCP)

衡量装载性能。为了提供良好的用户体验,LCP应该在页面首次开始加载后2.5秒内发生,即前2.5s内进行最大内容渲染。

2. 最大内容包括哪些?
  •   - <img>元素
  •   - <svg>元素
  •   - <video>元素
  •   - 通过url()函数加载的背景图片元素
  •   - 包含文本节点或者其他内联文本元素子集的块级元素
 3. LCP值低下的原因
  •   - 服务器渲染慢
  •   - 阻断渲染 JS和CSS 单线程主从机制互相block
  •   - 资源加载时间慢 静态资源
  •   - 客户端渲染机器的性能
优化方案: 针对性的改造
  1. 服务器优化:
  •  缓存html离线页面,缓存页面资源,减少浏览器对资源的请求消耗(强缓存、协商缓存)
  •  尽量减少阻断渲染:
  •  CSS和JS在文件层面进行压缩 合并 级联 内联,减少串联型处理,后置逻辑

    比如点击下一步的动作,可以放在第一步渲染完之后才做,把不必要第一次渲染的逻辑后置

  2. 图片和视频等资源优化:

      图片:格式优化:JPG和WEBP,降低图片的大小,加快请求的速度

      交互:点击播放键才播放视频,点击之前后台加载,优化一些用户体验

  3. 客户端优化

    文件解析方式:减少文件大小,减少逻辑操作,优化算法复杂度

      webpack plugin

    script标签里的async preload gzip

    服务端渲染同构

2. 衡量交互性  First Input Delay (FID)

为了提供良好的用户体验,页面的FID应该小于100ms

* 页面的首次输入延迟应当小于100ms

  刷新页面一定时间内input为什么不能输入?因为渲染没有完成,输入组件模块的加载没有完成,依赖于js 的执行。

优化方案:
  1. 减少js 的执行时间
  •     - 缩小并减少js文件的大小
  •     - 延迟或者取消部分不必须的逻辑文件,比如输入校验之类的逻辑,比如vue可以放在mounted之后再做一些处理,与doom的渲染错开
  •     - 尽量减少或者按需加载 polyfill 即逻辑嵌套
  2. 分解耗时的长任务

    - 任何阻塞主线程50ms以上的都可以称作长任务,

      将长任务拆分为若干较小任务并异步执行,或者后置到下次渲染开始执行

      比如settimeout转换为nextTick

        利用worker

    - js worker: web worker | service worker

    给我们一个小帮手,通过主从线程协作的方式把一个复杂的会阻塞主线程的方法简单化,获得更快的加载速度。

// 1. web worker
// main.js
// 新增worker
const myWorker = new Worker('worker.js')

//与main thread之间的通信
myWorker.postMessage('hello')
myWorker.onmessage = fuction(e) {
  console.log(e.data)
}
// worker.js
self.onmessage = function(e) {
  console.log(e.data)
  // 处理
  self.postMessage(workerResult)
}

  这样就可以将myworker中的一部分操作分发到worker.js里去做,将任务分解


service worker

// main.js
navigator.serviceWorker.register('./service-worker.js')
// service-worker.js
self.addEvenListener('intall',function() {
  // do sth
})
self,addEvenListener('activate',function() {
  // do sth
})
// 网络请求
self.addEvenListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
  )
})
// 面向网络和cache处理响应逻辑

如何区分这种网络请求和普通的axios请求?    

如果主从线程都需要用到一些请求,那么通常放到主线程里,将数据分发到从线程,如果从线程可以独立地做一套完整的请求和处理,就可以在从线程中发起请求,将后续操作返回给主线程即可。

3. 衡量视觉稳定性  Cumlative Layout Shift(CLS)

为了提供良好的用户体验,页面应该保持CLS小于0.1

* 布局的移动可能发生在可见元素从前一帧到下一帧改变的位置

如何优化
  1. 不使用无尺寸元素 特别是根据数据变化渲染的内容

    srcset & sizes

<img 
  srcset="img-320w.jpg 320w,
          img-480w.jpg 480w,
          img-800w.jpg 800w"
  sizes="(max-width: 320px) 280px,
          (max-width: 480px) 440px,
          800px"
  src="img-800w.jpg"
/>

    根据图片源可能的尺寸进行固定大小展示,不会因为变大变小而发生改变。

    2. 减少内部内容的插入,影响整体的布局

      比如大小固定后可以通过滚动等来控制,不会对布局产生影响

    3. 动态字体控制

      先默认字体展示占位,下载完成之后再动态替换

@font-face {
  font-family: 'xxx';
  font-style: normal;
  font-weight: 400;
  src: local('xxx Regular'), local('xxx Regular'), url('https://fonts.xxx.com/xxx.woff');
  font-display: swap;
}
<link rel="preload"> // 预加载字体

    这样就可以先用本地的字体展示出来,布局完成,等到远端字体下载完毕再去替换

CWV工具

  安装后可以在浏览器看到实时性能

  Core Web Vitals Annotations

性能优化的另一种可能性 - bigpipe - 页面分解成若干个pagelet

1. 服务前端接受来自客户端的http请求

2. 存储层缓存获取数据

3. 生成HTML,响应给客户端 + 客户端渲染

4. 动态区隔解析内容

大厂监控体系

  埋点上报 点到点 + 信息采集

  数据清洗 阈值设置 | 数据分类(加载 渲染 网络 操作类型的数据)不同维度的分析 | 数据重组 能够在展示平台展示的数据视图

  可视化展现

    自研报表监控

    可视化面板展示 grafana

  告警处理

    告警触发

    告警的分派 办公软件通知

面试tips:

结合自己的项目,你遇到什么样的问题,是怎么解决的,监控体系是怎么实现。

  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值