问答

不懂就要问,浏览器到底是什么时候更新dom?

作者:admin 2021-06-24 我要评论

求大佬拯救我 相信很多人看过这段话: 浏览器内核是多线程的,其中一个常驻线程叫javascript引擎线程,负责执行js代码,还有一个常驻线程叫GUI渲染线程,负责页...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

求大佬拯救我
相信很多人看过这段话:
浏览器内核是多线程的,其中一个常驻线程叫javascript引擎线程,负责执行js代码,还有一个常驻线程叫GUI渲染线程,负责页面渲染,dom重画等操作。javascript引擎是基于事件驱动单线程执行的,js线程一直在等待着任务列表中的任务到来,而js线程与gui渲染线程是互斥的,当js线程执行时,渲染线程呈挂起状态,只有当js线程空闲时渲染线程才会执行。

下面有我的三段测试代码:

document.querySelector('body').innerHTML = Math.random()
console.log(document.querySelector('body').innerHTML) 
var time = new Date().valueOf()
while(new Date().valueOf() - time < 2000) {}
// console是最新的随机数,页面2秒后更新
document.querySelector('body').innerHTML = Math.random()
console.log(document.querySelector('body').innerHTML)
Promise.resolve().then(()=>{
    var time = new Date().valueOf()
    while(new Date().valueOf() - time < 2000) {}
})
// console是最新的随机数,页面2秒后更新
document.querySelector('body').innerHTML = Math.random()
console.log(document.querySelector('body').innerHTML)
setTimeout(()=>{
    var time = new Date().valueOf()
    while(new Date().valueOf() - time < 2000) {}       
}, 1)
// console是最新的随机数,页面2秒后更新
document.querySelector('body').innerHTML = Math.random()
console.log(document.querySelector('body').innerHTML)
setTimeout(()=>{
    var time = new Date().valueOf()
    while(new Date().valueOf() - time < 2000) {}       
}, 100)
// console是最新的随机数,页面立刻更新

我的问题是:
dom什么时候更新?
同步代码和微任务执行完更新?好像不是。
js线程空闲的时候更新?好像是,那么什么时候算是js线程空闲?

###

简单的讲一下吧,说深了可能是一个大长篇。

其实这个很好理解,推荐先学习一下 requestAnimationFrame 这个API

其根本原因在于浏览器屏幕有一个相对稳定的刷新频率,理想情况是每秒60次。也就是 1000/60,大概16.66ms屏幕会刷新一次

根据浏览器的刷新屏幕,再对照上述代码 和 js线程 Gui线程理论 是不是马上就理解了呢

你的前三种情况,无论是同步还是微任务还是宏任务触发,因为都卡在了浏览器 绘制频率的时间内,后续都被js线程占有,停下了Gui绘制,所以结果是一样。 最后一种情况定时器的宏任务执行时间 足够浏览器屏幕更新大概五六次了,所以屏幕UI早就更新完毕了,后续才执行的 setTimeout宏任务

eventloop.png

###

DOM结构的修改是同步完成的,dom的实际效果修改或者说渲染是异步的,个人认为是同步js代码执行完毕和异步队列执行之前的中间段进行更新

###
document.querySelector('body').innerHTML = Math.random()
console.log(document.querySelector('body').innerHTML) 
var time = new Date().valueOf()
while(new Date().valueOf() - time < 2000) {}

这个的测试结果,调用栈空了在执行dom update,在下图的5500ms分界线。
image.png
这时候你会有个疑问说,为什么console.log先输出了。首先document.querySelector('body').innerHTML = Math.random()
console.log(document.querySelector('body').innerHTML) 你调用这个的时候,dom确实是已经改变了(我觉得可以简单理解为,dom对象数据已经改变,所以可以读出来),但是dom的改变不是说dom已经更新在界面了,这是两个概念,dom更新到页面上是要经过ui render之后;这个是render是在5500ms处,就是说等你的调用栈空了在去render的。因为js线程与gui渲染线程是互斥的
其他的你可以在chrome performance自己慢慢验证,

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 不懂就要问,浏览器到底是什么时候更新

    不懂就要问,浏览器到底是什么时候更新

  • antd4中的FormList怎么写多个表单项

    antd4中的FormList怎么写多个表单项

  • Finagle 和其他 RPC 协议之间的关系?

    Finagle 和其他 RPC 协议之间的关系?

  • wep2编译.wxss文件错误

    wep2编译.wxss文件错误

腾讯云代理商
海外云服务器