前言
- 常网IT源码上线啦!
- 本篇录入吊打面试官专栏,希望能祝君拿下Offer一臂之力,各位看官感兴趣可移步🚶。
- 有人说面试造火箭,进去拧螺丝;其实个人觉得问的问题是项目中涉及的点 || 热门的技术栈都是很好的面试体验,不要是旁门左道冷门的知识,实际上并不会用到的。
- 接下来想分享一些自己在项目中遇到的技术选型以及问题场景。
要明白客户需求啊。
东航的竞争对手,是国航吗?看上去,好像是的。但其实,东航真正的对手,可能是那个能用更便宜的票价、更舒适的体验、更准点的时间,把一个乘客从上海送到北京的高铁。当乘客发现,坐高铁的综合体验,比坐飞机更好时,他就会用脚投票,抛弃航空公司。航空公司,不是被另一家航空公司打败的。它是被一个“更好地满足了客户需求”的解决方案打败的。
轮船坐到对面,很惬意。
一、前言
说到性能优化,想讲讲requestAnimationFrame。
rAF是浏览器提供的专门用于动画渲染的API,它会在下一次浏览器重绘之前调用指定的回调函数。当显示器刷新率为60Hz时,浏览器会以约16.7ms(1000ms/60)的间隔触发rAF回调,从而实现60FPS的流畅动画效果。
function animate() {
// 动画逻辑
element.style.transform = `translateX(${position}px)`;
position += 2;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
-
垂直同步协调:rAF 与显示器刷新率同步,避免画面撕裂
-
智能节流:后台标签页自动暂停执行,节省CPU/GPU资源
-
批处理优化:浏览器将DOM操作合并到同一渲染周期
| 特性 | requestAnimationFrame | setTimeout |
|---|---|---|
| 刷新率同步 | ✅ 自动匹配屏幕刷新率 | ❌ 固定间隔(可能不同步) |
| 后台标签页暂停 | ✅ 自动暂停执行 | ❌ 持续执行 |
| 电池使用优化 | ✅ 智能优化能耗 | ❌ 无优化机制 |
| 帧率自适应 | ✅ 支持高刷新率屏幕(60/120Hz) | ❌ 固定帧率 |
直入正文。
二、60FPS是什么
人眼感知阈值:
-
15FPS:基本可识别为连续画面
-
30FPS:传统影视标准
-
60FPS:流畅交互的黄金标准
-
120FPS:专业游戏体验
布局抖动
// 反例:强制同步布局
element1.style.width = '100px';
const width = element2.offsetWidth; // 强制布局
element3.style.height = width + 'px';
// 正例:批量读写
requestAnimationFrame(() => {
element1.style.width = '100px';
const width = element2.offsetWidth;
element3.style.height = width + 'px';
});
图层管理策略:
.animating-element {
will-change: transform; /* 创建独立图层 */
transform: translateZ(0); /* GPU加速 */
}
三、nextTick 与 requestAnimationFrame
nextTick签名如下:function nextTick(callback?: () => void): Promise<void>
她是一个promise,所以我们可以await他,也可以放在回调函数中执行。
nextTick 和 requestAnimationFrame 都是异步调度机制:
-
Vue.nextTick:
在 DOM 更新循环之后 执行回调,主要用于在 Vue 数据变化后操作更新后的 DOM -
requestAnimationFrame:
在 浏览器下一次重绘之前 执行回调,专为动画设计,与浏览器刷新率同步(通常为 60FPS)
nextTick 是 Vue 的数据-DOM 同步机制
requestAnimationFrame 是浏览器的渲染时序控制机制
nextTick 解决的是'看到'的问题,requestAnimationFrame 解决的是'流畅'的问题。
完整执行顺序:
-
执行宏任务(script 整体代码)
-
清空微任务队列(Promise、nextTick)
-
执行渲染操作(rAF 回调、布局、绘制)
-
等待下一事件循环
他两干活,工作不累。
在涉及 DOM 更新的动画场景中组合使用两者
-
数据变更
-
Vue 的 DOM 更新队列
-
nextTick 回调(微任务)
-
requestAnimationFrame(下一帧渲染前)
-
浏览器绘制
// 最佳实践:DOM 更新后执行动画
Vue.component('example', {
methods: {
updateData() {
this.data = newData
Vue.nextTick(() => {
// DOM 已更新
requestAnimationFrame(() => {
// 执行基于新 DOM 的动画
element.animate([...], {duration: 300})
})
})
}
}
})
更新dom是异步吗?
js的更新dom是同步的,但vue修改数据后,并不马上修改,而是加入一个刷新队列(涉及到事件循环)。当你去获取修改后的值时,实际上vue还没有去修改dom,那自然取不到值。要想取到值,就得用nextTick,把回调函数放在dom更新之后执行,自然取得到值。
为啥不直接更新dom,因为修改dom可能会导致重排回流。
diff算法做法也是不想修改dom,才设计此算法。
四、浏览器兼容性处理
nextTick
// Vue 实际源码中的降级方案
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
}
} else if (typeof MutationObserver !== 'undefined') {
// 使用 MutationObserver
} else if (typeof setImmediate !== 'undefined') {
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
rAF 的 polyfill
// 兼容旧版浏览器
window.requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
return setTimeout(() => {
callback(performance.now())
}, 16)
}
至此撒花~
后记
现在或多或少对requestAnimationFrame和nextTick有所了解了叭~
我们在实际项目中或多或少遇到一些奇奇怪怪的问题。
自己也会对一些写法的思考,为什么不行🤔,又为什么行了?
最后,祝君能拿下满意的offer。
我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车
👍 如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
vue2和Vue3和React的diff算法展开说说:从原理到优化策略