同步CSS处理与异步alert执行顺序异常问题咨询
问题:alert为何先于CSS样式变更触发?
if(myTurn) { item.setAttribute('class', 'black'); } else { item.setAttribute('class', 'white'); } // 승리 체크 if (checkWin(row, col, turn)) { let winner = myTurn ? '흑돌' : '백돌'; setTimeout(function() { alert(winner + ' 승!'); location.reload(); }, 0); }
上述代码中,设置元素class为同步逻辑,弹窗alert为异步逻辑。实际运行时,alert会先于class对应的CSS样式变更出现;若将setTimeout的延迟设为10ms,则alert会按预期在样式变更后出现。
想咨询:是否因为异步alert的执行速度快于CSS变更?已了解事件循环执行机制,但无法理解alert为何先于CSS样式变更触发。
解答
核心原因不是alert执行速度比CSS变更快,而是浏览器的渲染时机和JavaScript任务队列的执行顺序问题:
- 同步修改元素class后,DOM结构会立刻更新,但CSS样式的计算、重排重绘(视觉上的样式变更)并不会即时执行——浏览器会将这类渲染操作推迟到当前JavaScript执行线程空闲时,也就是当前宏任务全部执行完毕后才会处理。
setTimeout(fn, 0)的回调会被加入宏任务队列,且会在当前宏任务结束后立刻执行,此时浏览器还没来得及触发渲染流程(渲染动作是在两个宏任务之间的间隙进行的)。因此alert弹出时,虽然DOM的class已修改,但视觉上的样式更新尚未完成,看起来就像alert先出现了。- 当把延迟设为10ms时,给了浏览器足够的时间在回调执行前完成渲染流程,所以样式变更会先显示,再弹出alert。
简单总结:同步修改class只是更新了DOM数据,视觉上的样式变化要等当前JS任务跑完;而setTimeout(0)的回调执行时机太早,抢在渲染之前弹出alert,导致你看不到预期的样式变更顺序。
内容的提问来源于stack exchange,提问作者Yechan Kim
相关产品推荐
相关产品推荐

