论坛首页 Web前端技术论坛

批量修改style采取哪种方式好(答fins)

浏览 10444 次
该帖已经被评为精华帖
作者 正文
   发表时间:2008-02-25  
问题再次延伸!

hax 写道
同等条件下,性能应该是改样式表要快。因为这个变更分发是由浏览器做的,肯定是native调用,比JS调用要快。


当 styleSheet 里的 class的内容变化时
浏览器内部是怎么刷新响应的页面元素的?
会不会是 遍历所有的 页面元素, 如果元素的class含有被改变的class那么就刷新?

如果是这样 那页面元素非常多非常多的时候 会不会出现比 js调用更慢的情况呢?

毕竟js调用是有目的的, 例如一个列表1000行 那么js遍历的就是1000个td
而native调用是遍历所有的页面元素.

也就是说 当页面复杂到一定程度 会不会出现native调用比js调用更慢的情况呢?




0 请登录后投票
   发表时间:2008-02-25  
i_love_sc 写道
col 只有ie才支持。


FF早就支持了。但是正如我之前所说的,它对于col/colgroup上的css prop的支持有限,比如它不支持col/colgroup上的text-align。它也不支持html规范中所列出的align属性,因为本质上,FF是一个CSS浏览器而不是一个HTML浏览器,所以如果一个属性的格式化要求无法被转化为CSS,则就不可能得到支持。也许因此造成你有印象FF不支持col。

但是这是有原因的,我一直想写一篇blog来分析一下这个问题,不过一直没写。各位可直接看https://bugzilla.mozilla.org/show_bug.cgi?id=915,你可以注意到这个bug的编号是915,也就是很老很老很老很老的一个问题,实际上日期是1998-09-26,也就是说,至少10年以前那个时候(那时候我还在用386混DOS,根本上不了网,要用浏览器还得钻学校机房2块钱1小时啊),Mozilla已经支持col,否则就没有这个bug了。简单的原因可以看CSS21作者hixie的解说。各位不喜看英文的朋友,可暂时看看这个:http://forum.moztw.org/viewtopic.php?t=3905
0 请登录后投票
   发表时间:2008-02-25  
fins 写道
问题再次延伸!

hax 写道
同等条件下,性能应该是改样式表要快。因为这个变更分发是由浏览器做的,肯定是native调用,比JS调用要快。


当 styleSheet 里的 class的内容变化时
浏览器内部是怎么刷新响应的页面元素的?
会不会是 遍历所有的 页面元素, 如果元素的class含有被改变的class那么就刷新?

如果是这样 那页面元素非常多非常多的时候 会不会出现比 js调用更慢的情况呢?

毕竟js调用是有目的的, 例如一个列表1000行 那么js遍历的就是1000个td
而native调用是遍历所有的页面元素.

也就是说 当页面复杂到一定程度 会不会出现native调用比js调用更慢的情况呢?


Great question.

我也想过这个问题,比如我修改了body上的一个class,到底会发生什么事情。这实际上得去看浏览器的CSS引擎是怎么实现的。我没看过,所以回答不能算权威。

现在我只能做一些大体定性的判断。

首先native调用通常比js调用要快上几个数量级。
其次,我原文也加上了“同等条件下”,如果浏览器需要遍历所有元素来判断class的话,那js程序也一样,如果js程序自己存着一个数组,而不做任何模式匹配,这个比较就不是同等条件了。不过考虑到native调用实在比js快,比如js做一个循环就要花上不少时间,所以基本上可以肯定还是native的快。
其三,CSS本来就是一个很复杂的机制(虽然用的人很爽),所以引擎必然做了很多优化,不会每次变化都去遍历所有元素,重新计算所有的规则和最终的样式。

比如,如果我来实现引擎的话,可能会让每个cssrule对象内部保持着所有适用rule的selector的元素的引用数组,然后如果rule的cssdeclaration发生变化,就通知每个元素重新计算cascade后的样式。按照我之前写的selector api,也许代码类似这样(用JS表示):

rule.selector.getAll().forEach(function(e){e.recalcStyle()});

而recalcStyle肯定也可以做优化,而不必重新计算所有该元素适用的rule。比如只需要计算原来的cssdeclaration和现在的cssdeclaration中有不同的css properties。计算完成之后,再把变更部分通知到render引擎,render引擎进行页面的重绘。注意,这里recalcStyle的计算过程,以及页面重绘过程都可以是异步的。

假如selector部分发生变化,就复杂一点,因为要重新匹配。然而,考虑到这件事情JS也能做,比如所有的JS类库的querySelector功能干的都是这个事情,他们的算法在不断优化性能不断提高,那native的实现不用说干起来肯定快上不知多少!比如说,有些优化,JS做不到或者很难办的,对于native来说却轻而易举,例如,你可以给所有的class做索引,从一个hashmap里根据className反查,这样一个带有class的selector匹配起来根本不用遍历所有元素。总之,这个selector查询问题,就跟sql查询一样,有很多优化可以做。

相比较而言,最困难的一点,大概是我所说的问题,修改了body上的一个class,也就是DOM元素或属性的结构变化,也就是我前面说的selector match/unmatch的监听问题。因为理论上,一个元素发生某种结构变化时,它本身,它的所有子节点,它的sibling节点(主要是后续的兄弟节点)及其子节点,所有这些节点的匹配都可能发生变化。所有这些节点的所有selector匹配都要重新计算。当然也可能存在某种优化方式,例如如果只是一个class变更,那么只需要计算所有selector中包含这个class条件的那些selector,但是窃以为这种优化如果超出class之外就实在非常的困难,也许反而不美。

然而这样困难的问题,在现在所有浏览器中都得到了解决,而且我们日常所最常用的方式,恰恰是修改class这样的操作。所以其他问题跟这个比起来,也许不值一提了。

顺便说一句,至少IE中,class确实是受到特殊待遇的。比如通过CSS绑定的htc,当selector匹配生效或失效的时候,样式虽然会立即生效或失效(实际是异步的),但是htc并不会被自动attach和detach,这一点有些奇怪,也许是出于性能考虑,也许根本就是一个bug。为了强制进行重新计算,你可以这样:
var all = document.getElementsByTagName('*');
for (var n=all.length, i=0; i<n; i++) {all[i].className+=''}

也就是,className的变更,会触发元素对于其本身适用的样式进行刷新。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics