当前位置: 首页 > Web前端 > JavaScript

dom更新发生在javascript事件循环的哪个阶段?《前端每日一题v22.11.17》

时间:2023-03-26 22:48:00 JavaScript

dom在javascript事件循环的哪个阶段更新?《前端每日一题v22.11.17》昨天写了一篇文章,是javascript的事件循环机制,然后贴在某网站上。贴的时候看到一个问题,dom渲染在事件循环的哪个阶段??看到这个问题,我冷冷一笑。这不是很明显吗?一定是事件循环中的异步任务队列。任务队列分为宏任务和微任务。dom更新发生在微任务队列清空之后,宏任务队列启动之前。结论谁都知道,但凡??事都需要实践。实践是检验真理的唯一标准。如何验证?我写了下面的代码,在异步微任务和宏任务之间添加了一个dom更新操作setTimeout(()=>{alert('pausepointalert');console.log('setTimeoutdone')},0)document.getElementsByTagName('div')[0].innerHTML='FEIntelligenceAgency'newPromise((resolve)=>{resolve()}).then(()=>{console.log('promisedone')})其中,我在宏任务的开头加了一个alert来屏蔽js,观察页面是否已经有FE情报机关。当我满怀信心地按下去时,页面是空的。我傻眼了,按下Confirm之后,页面上显示的很奇怪,结论和我预想的不一致!!!找到原因以为发现了巨大的bug,于是疯狂搜集资料,发现所有的结论都是dom更新确实是在microtask之后,为什么性能不一致呢?浏览器没有及时更新?于是在弹出alert的时候查看dom元素,发现虽然页面上没有dom元素,但是dom元素已经正常在DOM上了,这就涉及到另外一个问题,浏览器GUI线程UI线程的更新机制而js众所周知,浏览器对js的处理主要在js线程,页面渲染主要在gui线程。由于js可以操作dom元素,所以js会影响页面渲染,即会影响gui线程的渲染结果。这样,这两个线程就不能同时工作了。一旦它们同时起作用,相互影响就会造成难以预料的后果。因此,在浏览器中,js线程和gui线程是互斥的,只允许一个线程处理任务执行。当js线程运行时,gui线程不会运行。有了这个基础,我们在讨论动画,这里涉及到一个概念,就是刷新率。我们经常听到刷新率这个词。比如我们电脑屏幕的刷新率达到120Hz,或者玩游戏的时候经常有一个词叫做FPS。刷新率是指显示器每秒绘制新图像的次数。60Hz表示浏览器每秒绘制60次。由于人眼的暂留效应,我们可以看到流畅的动画。如果你的刷新率只有10次/秒,你会发现你看的动画和ppt一样,很卡关系,我们可以理解为浏览器要在16.6毫秒内完成js脚本和浏览器渲染。回到主题,很容易理解。我们刚开始执行js代码的时候,虽然我们看元素下的dom已经更新到dom树了,但是浏览器还没有刷新,所以本质上是没有显示的,但是我一直认为是它造成的通过警报,所以我使用了另一种方式setTimeout(()=>{for(letindex=0;index<1000000;index++){if(index===1000000-1){console.log('end')}}console.log('setTimeoutdone')},0)文件。getElementsByTagName('div')[0].innerHTML='FEIntelligenceAgency'newPromise((resolve)=>{resolve()}).then(()=>{console.log('promisedone')for(letindex=0;index<1000000;index++){if(index===1000000-1){console.log('done')}}})这时候你会发现dom在进入setTimeout之前,done之后已经渲染到浏览器了,一开始直接显示的部分原因是alert导致的,所以换成普通的阻塞进程的js没问题。欢迎大家留言讨论。是不是因为alert机制,微任务结束后,宏任务中的alert阻碍了dom的渲染,导致UI线程不能及时刷新?