逐行解析DOM展开折叠动画Javascript代码,厘清其中while循环的实际作用
animateHeight 函数逐行执行逻辑全解析 函数定义与入参与初始化阶段
逐行对应代码逻辑:
function animateHeight(children, animationDuration, changeTop) {
定义展开/折叠动画工具函数,接收三个入参:children:执行位移动画的目标DOM元素animationDuration:动画总时长(单位为毫秒)changeTop:自定义位移计算回调,传入当前累计移动距离、元素总高度,返回当前帧需要设置的top属性值,通过回调差异实现展开/折叠的不同位移方向
const height = children.clientHeight;
读取目标元素的当前可见高度,作为整个动画的总移动距离基准。const frameDuration = (1 / 60) * 1000; // 60 fps
计算60fps帧率对应的单帧最小间隔时长(约16.67毫秒),作为后续控制DOM刷新频率的时间阈值。
异步动画流程的Promise封装
return new Promise((resolve, reject) => {
将完整动画流程封装为可异步等待的Promise对象,动画执行完成后触发resolve回调,方便外层代码在动画结束后衔接后续操作。const slideSomeMore = function (moved) {
定义递归执行的帧更新函数,入参moved表示当前已经累计的移动距离,从0开始逐步累加,直到等于总高度height时终止动画。
核心卡点:slideSomeMore 内部循环的真实运行逻辑
这部分是理解的断点,实际执行逻辑和直觉上的“同步跑完全程循环”完全不同:
let next = window.performance.now() + frameDuration;
计算当前帧允许执行下一次DOM更新的最早时间点:取当前高精度时间戳,加上单帧间隔阈值frameDuration,即距离本次函数调用的时间,过16.67毫秒后才允许触发下一次DOM样式更新。while (moved < height)循环的实际执行逻辑:- 循环触发条件是“累计移动距离还未达到总高度”,代表动画尚未执行完成。
- 循环内部的判断分支
if (window.performance.now() < next) { continue; }:
检查当前时间是否早于之前计算的最早可更新时间。如果未到时间,就执行continue回到循环开头,不做任何DOM操作,同步空转等待时间到点。注:这种同步忙等的写法会阻塞JS主线程,是代码本身的性能缺陷,但从设计意图上,是为了把刷新频率控制在60fps附近,避免过度操作DOM。
- 当时间到点(当前时间 >= next)时,跳过空转分支,依次执行两步操作:
- 调用
changeTop回调,根据当前累计移动距离moved、总高度height计算当前帧的top属性值,直接赋值给children.style.top,完成一次DOM样式更新。 - 计算下一帧的累计移动距离:
moved = moved + height / animationDuration。这个值的逻辑是“总高度除以动画总时长”,算出每毫秒需要移动的固定距离,保证动画整体执行时长和传入的animationDuration一致,实现匀速位移。
- 调用
- 完成上述DOM更新和距离累加后,立刻执行
setTimeout(() => slideSomeMore(moved), 0);,把当前累计的moved值作为参数,将下一帧的更新逻辑放入宏任务队列,随后直接执行return退出当前循环和函数,终止同步执行流程。
- 循环为什么不会“卡死在同步栈里跑完所有帧”?
因为每次更新完一帧的DOM后,代码会立刻通过return跳出同步循环,把后续的递归调用扔给宏任务异步触发。当宏任务队列里的slideSomeMore被执行时,会重新计算新的时间阈值、再走一遍“时间检查-更新DOM-累加距离-异步递归”的流程,直到累计的moved值大于等于总高度height时,不再进入while循环,直接执行resolve()结束整个Promise流程。
启动入口
slideSomeMore(0);
以初始累计移动距离0为参数,触发第一帧的动画执行流程,正式启动动画。
整体执行机制总结
- 本代码没有使用标准的
requestAnimationFrame接口,而是通过“同步忙等控帧+setTimeout递归”的方式,实现接近60fps的匀速展开/折叠动画; - 动画全程累计移动距离等于元素本身的高度,通过传入的
changeTop回调自定义位移方向,区分展开、折叠的效果; - 异步封装的Promise可以让外层代码清晰感知动画的结束时机。
内容的提问来源于stack exchange,提问作者spraveenitpro
相关产品推荐
相关产品推荐

