我想知道浏览器的渲染过程,JS线程与UI线程是怎么交互的?
最想知道什么样的样式操作,会被合并到一次渲染中。
例如我想一个图片hover的时候即刻变小,然后过渡放大到原来大小
p.onmouseover = function(){
p.className = 'small';
p.className = 'transition'
}
但浏览器会将上面两个操作合并了成p.className = 'transition',而没有分别渲染两个效果,
所以很想了解浏览器的渲染过程,以及JS什么时候会让浏览器渲染?
Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
有人说是因为电脑运行太快,你没有看到,这个回答是错误的。
如果是因为这个原因,你可以试着把代码改成这样,看看是什么样子:
结果是,网页将会在卡住短暂时间之后渲染出
p.className = 'transition'的效果。这方面我也没有找到相关的资料,但是我自己试验过很多代码,得出一个结论:网页的渲染是在脚本主进程结束之后才会进行。(虽然不知道是不是完全正确,但是个人觉得能和我观察到的现象相符合,如果不对还请指正)
也就是说,对于你的代码而言,虽然你给
className赋值了两次,但是实际上只有当主进程结束之后网页才会重新渲染,而那时候你的className是等于transition的。如果你想要看到两个
class的效果,那么就要给两次赋值中间将主进程空闲出来留给网页渲染。这就需要异步的过程。代码只需要改成这样就行了:setTimeout这个异步函数将会给主进程空闲出5秒的时间用于网页渲染,这样你就能看到两个效果了。事实上浏览器的渲染是周期,并不是每时每刻都随着dom的变化进行渲染,所以当你两次变化间间隔太短,就会在同一个渲染周期之中,自然只会有最后一个的变化。
我也来补充一下。。。
浏览器里面存在两个线程,请允许我叫他们为:渲染哥和js哥。
很明显,渲染哥就是负责渲染web页面的工作,比如css和html结合后的dom树再进行渲染,或者开启@keyframe动画,还是简简单单的transition,都是渲染哥在负责计算和绘制的。
而我们的js哥呢,顾名思义,就是只是处理一下js代码,然后将处理结果提交给渲染哥渲染(假如出现变动的话)。
因为浏览器里面只有一张办公桌(堆)和一张椅子(栈),对于包吃包住在浏览器里的渲染哥和js哥来说,就只能一个人工作另一个人休息了,所以他们优化了他们的工作模式:平时没什么事的时候渲染哥在办公桌(堆)工作,当浏览器读到JS代码的时候,渲染哥把办公桌让给JS哥搞,他自己坐在椅子上,当JS哥处理完代码,又重新将办公桌让给渲染哥。
但真正让渲染哥和js哥交接工作的,是事件。
我们知道,JS的事件驱动的,很懒,没有事件发生的时候似乎天塌下来也跟他无关。一旦页面存在相关事件,且被用户触发了,这时候渲染哥很高兴啊,立马通知JS哥上班,自己拍拍屁股下班了。
然后在JS线程工作期间,如果JS哥遇到了 @外籍杰克 所说的
p.clientHeight这类强制重绘的代码,就会让渲染哥画一遍后再获取它。最后指出一下你那个className的错误。。。并不是说什么帮你合并了class,而是你自己把className给替换了。
而那个
setTimeout的嘿嘿,这样呢
p.class = a;
setTimeout(function(){p.class=b},0);
p.className ="…";这样可以吗,好像没见过这样写的
这是浏览器渲染优化的一个手段。
也就是说,当你在运行一段JS代码时,浏览器并不会每一次改动就渲染页面,而是会将这些改变缓存下来,直到代码运行之后才会将这些改变进行渲染。
所以你的代码缓存后就变成
transtion了。这篇文章应该能完美的解决你的疑惑。
往往我们在操作Dom的时候,应该尽量连续的写操作,或连接的读操作,而不应该读一个值,写一个值,这样如果涉及到需要重绘的值,那么对性能影响很大。因为浏览器会对连续的操作一次性处理。
那么针对题主的问题,两次更新Class,需要重绘两次才会得到预期的效果,只需要在中间做一次读操作就行了。
为什么会这样,原理很简单,因为如果我们先改了p的样式,然后再去读取它的某个值,因为样式变了会导致很多属性值会变,比如高,宽等等,那浏览器需要返回给我们正确的值,就必须先强制对前面的操作重绘。