页面优化

1、重定向优化,尽量少用301和302,如果遇到重定向,可以吧重定向之后的地址直接填写到前端的html和js中。
2、利用缓存(304,本地缓存策略)
3、DNS优化,尽量把各种资源都放在一个CDN域名上;DNS预获取
4、TCP减少请求数量,合并请求
5、HTTP请求优化。使用内容分发网络CDN,减少网络的请求延时。对于网络请求,使用fetch发送无cookie的请求,减少http包的大小
6、渲染优化

面试重点:

1、算法
2、底层原理

前端性能优化CRP(关键渲染路径)

1、URL解析

地址解析和编码,a、hsts 缓存检查

2、DNS解析,得到外网IP地址,(20-120ms)

1、本地解析:浏览器缓存,本地操作系统host,本地 DNS解析服务器,递归
根域名服务器-顶级域名服务器-权威域名服务器-当前外网服务器的地址,迭代
优化点:1、减少dns请求次数,(一个网站需要从多个服务器返回资源),这点优化很难,负载均衡
2、dns预获取。设置dns-prefetch

3、TCP三次握手

4、发送http请求

优化点1、减少http请求的次数,具体操作
资源合并压缩;字体图标;base64,不要滥用;开启GZIP;图片懒加载;数据延迟分批加载;CDN资源,请求最近资源;骨架屏
2、利用浏览器缓存,公共依赖包单独打包,避免重复请求
3、减少cookie大小,尽量使用localStorage代替(cookie会随着浏览器请求发送服务端)

5、服务器处理响应

6、TCP四次挥手

7、浏览器渲染

1、构建DOM树
转换-令牌-词法分析-dom构建
byte-characters(字符集)-tokens-notes-dom
优化点:1、标签语义化
2、尽量避免深层次的嵌套

—-AST
2、CSSOM树
link 会发送http请求,异步的单独线程去处理,chorme6-7个,主线程依旧执行(dom继续渲染)
@import ,同步的,会阻塞dom渲染
style不发请求,但是如果过大,会影响拉取html的速度,不多的情况下可以使用style,比link优,link要写在头部,尽早的把css下载带客户端(利用http多请求的并发机制)
优化点 1、选择器查找是从右向左的,避免选择器层级太多,尤其是less\sass避免滥用层级嵌套
2、减少@import的使用
3、js默认是阻塞主流程的,一般js放到底部
defer:等渲染完了才去执行js,建议用
async:回来的就先执行js,所以不能设置依赖
4、元素的样式改变,引发重绘,重绘不一定引发回流(重排)
5、元素的大小和位置改变会引发回流(重排,几何属性更新),回流一定引发重绘(样式更新)
6、减少dom的回流(重排)和重绘,(框架已经不太需要,vue,react)【添加dom节点时,1、使用文档片段创建,再添加到dom中(1次重排)2、隐藏元素,修改完成后再进行显示(2次重排)。3、将原始节点拷贝,操作后再覆盖原始元素(1次重排)】
7、分离读写,样式集中改变(批量修改),缓存布局信息(比如offsetLeft,clientTop。缓存DOM节点也是同理,减少dom访问次数),元素批量修改,或者使用className,动画效果应用到position属性为absolute或者fiexd的元素上(脱离文档流),css硬件加速(GPU加速),避免table布局,
8、使用transform代替top,一个是基于文档流位置的变动,另一个是基于自身的视觉变动,其本身位置并没有改变;position设置的是DOM的样式,实现动画效果将同时消耗CPU和内存,而transform使用的是显卡。
9、使用visibility代替dispaly:none,前者只会引起重绘。后者会引起回流
10、不要把DOM放在循环中作为循环变量
11、将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行文影响别的节点。比如video标签,浏览器会自动将该节点变为图层
tips:设置节点为图层的方式:
will-change
video、iframe标签
12、合并css,减少HTTP请求,css文件放在最上面,充分利用继承性,抽取公共样式,移除空css规则,避免使用css表达式(因为每次调用都会重新计算值,包括加载页面),css Sprites,css避免节点层级过多(从右向左匹配)
以下几个操作可能会导致性能问题
a、改变 window大小
b、改变字体
c、添加或删除样式
d、文字改变
e、定位或者浮动
f、盒模型
3、生成渲染树
4、浏览器根据生成的渲染树,计算他们在设备视口内的确切位置和大小,回流(布局layout)\重排
5、根据渲染树以及回流得到的几何信息,得到节点的绝对像素=》绘制\栅格化

8、应用缓存

1、浏览器请求资源前先检查缓存—》是不是强缓存—》没过期—》走缓存,不会发送请求到服务器了
过期—》发送请求到服务器=》服务器http再验证=》走协商缓存(在强缓存之后)
强缓存:不发送到服务器
协商缓存:发送请求到服务器,如果命中,不返回资源,告诉浏览器从缓存中取
补充http协议中关于缓存的字段
强缓存: expires:值为绝对时间的GMT格式,代表资源的过期时间,属于http1,(如果服务器和浏览器时间不准,判断就有偏差,所以有了Cache-Control)
Cache-Control:值max-age,单位为秒,指资源的最大生命周期,http1.1,优先级更高,
服务器部署设置的,例如ngix;
如果文件有更新,设置hash值,换名字,走新的请z求
协商缓存:返回304
Last-Modified:值为资源的最后更新时间,随着服务器response返回,告诉客户端资源的最后修改时间
If-Modified-Since:值为浏览器端缓存页面的最后修改时间,会发送给服务器,服务器对比这2个时间(浏览器端缓存页面的最后修改时间和服务器上文件修改的时间,如果不一样,返回200和新资源,并将服务器上文件修改的时间作为 Last-Modified的值返回给浏览器),
Etag:值 为表示资源内容的唯一标识,随着服务器response返回
If-None-Match:上一次服务端发送过来的Etag, gggggggg服务端对比两个标识,如果为False,返回304
注意: Last-Modified、If-Modified-Since 这一对是老版本的
Etag、 If-None-Match 这一对是新版本的
Etag是为了解决1、时间变了但是内容没变2、If-Modified-Since只能检查到秒,修改很频繁的检测不到3、某些服务器不能精确的得到文件的最后修改时间
强缓存和协商缓存是针对于文件的
针对数据:本地缓存,localStroge

1、缓存位置:server wokers
memory Cache:内存缓存,读取数据比硬盘快
硬盘缓存,disk Cache,存东西多
push Cache,推送缓存,http2中的

2、读取:第一次输入网址请求,从硬盘缓存读,
f5 刷新是走的内存缓存(会跳过强缓存,但是会检查协商缓存)
强制刷新,Ctrl+f5,走服务器
补充
打开新窗口:Cache-control值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:Cache-control: max-age=5(表示当访问此网页后的5 秒 内再次访问不会去服务器,如过期,然后走协商?)
地址栏回车:值为private或must-revalidate则只有第一次访问时会访问服务器,以后就不再访问。值为no-cache,那么每次都会访问。值为max-age,则在过期之前不会重复访问,如过期,走协商?。
按后退按扭:值为private、must-revalidate、max-age,则不会重访问,值为no-cache,则每次都重复访问
后续知识补充:1、http1.http2,https
nigix部署,以及缓存设置
代码运行优化,减少闭包
使用浏览器监测性能(性能评级工具。chrome:PageSpeed; fireFox:YSlow)
代码编译优化,webpack
安全优化

9、js相关优化

1、节流,防抖(手写)
2、长列表滚动到可视区域动态加载(大数据渲染)
3、图片懒加载(data-src)(判断元素是否出现在视野中:元素相对于顶点的距离offsetTop<= 窗口高度clientHeight+滚动距离scrollTop)
4、使用闭包时,在函数结尾手动删除不需要的局部变量,尤其在缓存dom节点的情况
5、批量添加dom,可先createElement创建并添加节点,最后一次性加入dom;批量绑定事件,使用事件委托(利用事件冒泡),减少内存优化,还可以动态绑定事件
6、如果可以,使用innerHTML代替appendChild(适合大规模使用时,但是里面的脚本会有条件才能执行,)
7、在DOM操作时尽量增加class属性,而不是通过style来操作,减少重排

10、重绘和回流(重排)和eventloop的关系

1、当Eventloop执行完一轮宏任务以及这轮所有微任务后,会判断document是否需要更新,因为浏览器是z的刷新率,每16.6ms才会更新一次
2、然后判断是否有resize或者scroll事件,有的话会触发事件,所以resize和scroll事件也至少是16ms菜触发一次,并且自带节流功能
3、判断是否触发了media query
4、更新动画并且发送事件
5、执行requestAnimationFrame回调
6、执行IntersectionObserver回调(该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好),然后更新页面
7、以上就是一帧中可能会做的事情,如果在一帧中有空闲事件,就会去执行requestIdleCallback回调

11、首屏加载优化方案

1、Vue-router路由懒加载(利用weblack的代码切割),vue异步组件
下面是代码实例

  1. //方案1,使用vue的异步组件,一个组件生成一个js文件
  2. {
  3. path: '/home',
  4. name: 'home',
  5. component: resolve => require(['@/components/home'],resolve)
  6. },{
  7. path: '/index',
  8. name: 'Index',
  9. component: resolve => require(['@/components/index'],resolve)
  10. },{
  11. path: '/about',
  12. name: 'about',
  13. component: resolve => require(['@/components/about'],resolve)
  14. }
  15. //方案2,路由懒加载,同react的lazy(),加载过程中还可以使用suspense提供一个loading状态
  16. //
  17. // 下面代码,没有指定webpackChunkName,每个组件打包成一个js文件。
  18. /* const Home = () => import('@/components/home')
  19. const Index = () => import('@/components/index')
  20. const About = () => import('@/components/about') */
  21. // 下面代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
  22. const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
  23. const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
  24. const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
  25. {
  26. path: '/about',
  27. component: About
  28. }, {
  29. path: '/index',
  30. component: Index
  31. }, {
  32. path: '/home',
  33. component: Home
  34. }
  35. //方案3,使用webpack的require.ensure()
  36. {
  37. path: '/home',
  38. name: 'home',
  39. component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
  40. }, {
  41. path: '/index',
  42. name: 'Index',
  43. component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
  44. }, {
  45. path: '/about',
  46. name: 'about',
  47. component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
  48. }
  49. require.ensure(dependencies: String[], callback: function(require), chunkName: String)
  50. //参数说明
  51. dependencies:字符串数组,在回调函数执行前,我们可以将所有需要用到的模块进行声明
  52. callback:当所有的依赖都加载完成,webpack会执行这个回调函数
  53. chunkName:设置相同的chunkName会被打包到一个js文件
  54. require.ensure()的坑,待补充

2、使用CDN加速。将通用库从vendor进行抽离
3、Nginx的gzip压缩
4、服务端渲染SSR
5、如果使用了UI库,按需加载
6、webpack开启gzip压缩,
7、如果首屏为登录页,可以做成多入口?
8、图片懒加载
9、页面使用骨架屏?webpack有骨架屏生成插件
10、利用号sxript标签的async和defer属性。功能独立且不需要立马执行的js文件,可以加入async属性。如果是优先级低并且没有依赖的js,可以加入defer属性

12、性能查看

performance.timing看各个步骤的耗时:白屏时间:performance.timing.responseStart - performance.timing.navigationStart

参考链接:https://juejin.cn/post/6844903688390049800

性能优化课程学习资料

性能测试工具

linthouse ,perfomence,在线测试工具如webpageTest (可在线可本地部署,本地部署就可以开发的时候调试)

各种性能指标

优化方式

关键渲染路径

性能优化分类

vue按需加载
打包监控和分析
webpack Chart
souce-map-
speed-measure-webpack-plugin

react的路由懒加载

  • React-loadable 结合react-router 和webpack
  • 基于路由的按需加载比较合理

网络传输

  • gzip——nginx开启压缩的方式 可达90%

    1. gzip on; //开启
    2. gzip_min_length 1K;
    3. gzip_comp_level 6; //压缩级别 1-9
    4. gzip_types text/plain application,javascript //等等,一般进行文字类压缩,图片一般不靠gizp来压
    5. gzip_static on; //已经压缩了的静态资源
    6. gzip_vary on; //告诉浏览器我们开启了压缩
    7. gzipz_buffers 4 16K; //优化这个压缩
    8. gzip_http_version 1.1 //http的版本
  • 启用keep-alive———1.1默认开启,也是nginx里的配置

keep-alive_timeout 65;
keep-alive_requests 100;

  • http资源缓存

    1. 需要配置expire强缓存的过期时间<br />nginx默认是开启了协商缓存etag/如果catch-control设置的是no-store,表明还要走默认的协商。如果设置的<br />no-catche ,直接不使用缓存,强制和协商都不要<br />catch-control:private/public private???
  • service-workers ,会延长首屏时间,但是总体加载时间减少,另外就是兼容性问题,只能在loachost和https上使用

  • http2
  • 服务端渲染,适合官网这种SEO 要求高的,大型面向公众,并且有很多动态数据的

前沿解决方案
  • 移动端svg