上一篇主要针对的是资源在传输过程中的优化,接下来我继续看看前端还能从什么角度去优化。
文章的demo
资源解析优化
js阻塞
在浏览器中把线程分为很多类,其中负责页面渲染的叫GUI 渲染线程
,负责js解析的叫JS 引擎线程
,GUI渲染线程在页面发生回流、重绘时才会触发,它与JS引擎线程属于互斥线程:在同一时间内浏览器只能执行其中的一个线程,如果GUI渲染线程和JS引擎线程其中一个被执行,那么另一个线程将被挂起,等到执行的线程执行结束再执行。
由于这个特点,所以我们在写html过程常常会考虑把script放在body的最后,css放在head中,这样浏览器在执行时会先解析css,再解析html,等到页面内容渲染结束即GUI渲染线程结束时再执行js,避免了因为JS引擎线程中断了GUI渲染线程造成页面渲染不连贯、卡顿的现象。
如在webpack中,用html-webpack-plugin可以通过设置inject
控制script输出位置:
回流与重绘
-
回流 (Reflow):当页面中的元素的结构、尺寸、位置发生改变时,浏览器计算元素的几何信息过程。
触发回流的一些操作:
- 页面首次渲染的时候。
- 对可见dom(display不为none)的增删改。
- 修改字体大小。
- dom位置尺寸变化(transforms除外)
- js查询某些属性或调用某些方法,详细的可以点击这里查看。
-
重绘(Repaint):将元素的几何消息转换为绝对像素供GPU渲染。
从上面可看出,在浏览器的渲染线程中,回流处于重绘之前,回流必触发重绘,重绘不一定会引起回流 ,回流的代价远比重绘的代价高,因此在代码设计过程中我们应该尽量的减少回流操作。具体可以从以下几点入手:
-
寻求避开回流的替代方法:
如在js控制dom移动位置可以尝试通过transform替代left、top定位。
-
合并回流操作:
当回流不可避免时,可以尝试合并操作,减少回流次数。举些栗子:
-
减少回流范围:
使用绝对定位,让dom脱离文档流,阻断回流向上层传播。
惰性加载
惰性加载也叫按需加载、被动加载,不主动去加载资源,只有需要再加载。这种优化主要针对于短时间内需要加载很多资源的情况,如图片列表、视频、首屏渲染等,通过对资源分割多段,再根据用户的环境需求判断优先加载哪段资源,从而减少单点资源大小,增加响应速度。
降低dom树的复杂度
降低dom树的复杂度可以加快浏览器对dom的解析、操作、响应速度。主要从深度和广度两个维度思考,减少没用的html标签嵌套,对数据量较大、结构较复杂的列表采用虚拟列表(监听滚动条滑动,去除屏幕暂未显示的列表节点,通过空白dom或margin或padding拉开滚动条)。
其他优化
优化算法
算法是所有程序员整个职业生涯的必修课,需要我们在工作学习的过程中不断推敲积累优化,它属于奠基层,决定上层建筑关键。它不是一成不变,没有最好的算法只有最合适的算法。
数据缓存
在开发过程中我们会遇到一些需要频繁复杂的纯函数运算,这些函数结果只与函数入参有关,此时我们可以考虑在把入参与结果储存起来,调用时先从结果集里查找有没有相关的入参,有则直接返回,没有再进行运算,这样就可以大大降低重复计算时的时间成本,这就是Memoization技术。
平滑过度
再精妙、完美的性能优化也不可能让动态系统达到0延迟,在用户的角度来说,他们更希望我们的系统是"有求必应",系统必须在极短时间内对用户的行为有所反馈,所以在结果未呈现给用户中间的真空期里我们可以适当“反应”暂时吸引用户的目光,为数据计算传递争取足够的时间。常用的方法如骨架屏、loading动画、渐进式图片等。
最后再bb几句
以上列举的是相对比较通用优化手段,在实际开发过程中,通常优化大多数都是带有一些副作用(如消耗更多内存换取更快的速度,消耗更大的算力换取更灵敏的响应),所以在开发过程中我们需要拿捏一下优化的尺度,不能生搬硬套,更重要的是发现优化的本质、为什么要这样优化、解决什么问题。在项目中发现问题,对症下药,需要对整个业务需求进行评估,选取比较适合的方案进行优化。
如果需要补充,欢迎告知我,一起学习,一起进(lao)步(jin)。