尽可能压缩每个阶段的执行时间或跳过某些阶段的执行;
渲染过程:
js处理,计算样式,页面布局,绘制与合成
不同浏览器的内核不同,在属性变化时触发的流程也不一样;
1.优化js执行
用 window中的requestAnimationFrame:将回调函数的执行时机交给系统来决定,与系统的刷新频率相关;
let start;
// 定义目标动画元素
const element = document.getElementById('MyAnimate');
element.style.position = 'absolute';
// 定义动画回调函数
function updateScreen(timestamp){
if(!start) start = timestamp;
// 根据时间戳计算每次动画位移
const progress = timestamp - start;
element.style.left = '${Math.min(progress/10,20)}px'
if(progress<2000)window.requestAnimationFrame(updateScreen)
}
// 启动回调函数
window.requestAnimationFrame(updateScreen)
这样的方法除了可以防止丢帧,还可以通过节流不必要的函数执行节省CPU性能;
setInterval 除非clearInterval,否则在后台的动画就会不断的执行
函数节流:一个刷新时间间隔中多次执行其实是没有意义的。
1.2:web worker
将一些纯计算放到webworker中去
主线程创建worker子线程,可以分担一部分执行任务,当子线程执行结束之后,返回结果给主线程;
worKer子线程一旦被创建,就会一直执行,不会被主线程的函数打断,所以非常的耗费资源,故而要适当使用,不可以过度使用。一旦任务执行完毕就要及时关闭;
web worker子线程有以下限制:
01.DOM限制:无法读取主线程的DOM,也就无法使用document,window,parent等对象,只能访问到navigator和location对象。
02.文件读取限制:worker子线程无法访问本地文件系统,要求所加载的脚本来自网络。
03.通信限制:主线程和worker子线程不在同一个上下文内,所以无法进行直接通信,只能通过消息来完成;
04.脚本执行限制:虽然可以通过XMLHTTPRequest对象发起ajax请求,但不能使用alert()方法和confirm()方法在页面弹出提示。
05.同源限制:必须与主线程代码同源
子线程处理完成后要及时在主线程调用 worker.terminate()方法关闭,在子线程调用self.close()方法来关闭;
如果所要处理的事件必须在主线程完成,那就考虑把大型任务拆分成微服务;(搞一个任务队列)
1.3事件节流与事件防抖
事件节流:如果超出节流时间,则触发回调函数;
事件防抖:首先设置一个防抖事件间隔,当事件开始触发后启动计时器,再次触发只更新计时器,不响应回调函数,只有当计时器完整计时结束后,才去响应执行最后一次事件触发的回调函数;
但是也要注意防抖节流中和用户的交互,防止用户耐心耗尽;
利用浏览器调试工具 分析影响性能的瓶颈 performance,more tools;
尽量拆分或者移除长时间执行的js脚本,放到web worker中
3.计算样式优化
我们写样式是从左往右,但是css选择器匹配是从右往左执行的,
用类选择器代替标签选择器;
避免使用通配符选择器,因为浏览器需要去遍历页面上的每一个元素,这样性能开销很大;
降低选择器的复杂性;
使用BEM规范;
块:.myList
元素:.myList--->.myList__item{}
修饰符:.myList__item_big{} 单下划线:作为描述一个块或其子元素的一种状态
中画线:-仅仅作为连字符使用
MEM样式编码规范要求所有元素都被单一的类选择器修饰,不仅清晰,查找简化,性能提升;
4.布局与重绘
重排和回流
重绘 仅仅改变样式;
尽量避免使用js对样式进行频繁的修改;
如果必须要修改:
01.使用类名对样式逐条修改;将多行的样式合并到一个类名上,改变类名。
mydiv.classList.add('my-div')