-
jQuery Bug: Defective Clone
-
I tried to append several dynamic tables to a DIV container and found something interesting.
<div id="divContainer">
<table></table>
</div>
<script type="text/javascript">
$(function() { var div = $("#divContainer"); var table = div.find("table"); var c = 0;
for (var i = 0; i < 3; i++)
{ table = table.clone();
div.append(table);
}
alert(div.children().length);
alert(div.html());
});
</script>
What will 'div.children().length' be? It should be 4 in this case, but you will get 3 in IE7 and 4 in Firefox 3. The 'alert(div.html())' provide more detail. In IE7, the div.html() looks like this:
<TABLE jQuery1218765772477="227"><TBODY></TBODY></TABLE>
<TABLE jQuery1218765772477="228"><TBODY jQuery1218765772477="null"></TBODY></TABLE>
<TABLE jQuery1218765772477="null"><TBODY jQuery1218765772477="null"></TBODY></TABLE>
<TABLE jQuery1218765772477="null"> <TBODY jQuery1218765772477="null"></TBODY></TABLE>
And div.html() will return blow result in Firefox3:
<table></table><table></table><table></table><table></table>
It seemed that jQuery added additional identification information (jQuery1218765772477 attribute) in IE and some of them are 'null'. After more experiments, I found if I modified the code to:
table2 = table.clone();
div.append(table2);
I got div.children().length==4 and
<TABLE jQuery1218765990513="231"><TBODY></TBODY></TABLE>
<TABLE jQuery1218765990513="232"><TBODY jQuery1218765990513="null"></TBODY></TABLE>
<TABLE jQuery1218765990513="233"><TBODY jQuery1218765990513="null"></TBODY></TABLE>
<TABLE jQuery1218765990513="234"><TBODY jQuery1218765990513="null"></TBODY></TABLE>
Every table got a unique jQuery1218765990513 attribute, so the jQuery.unique() didn't filter out the extra 'null' attribute table object . I don't think "table = table.clone()" is illegal syntax and this should be a bug of jQuery.clone().
I just submitted this bug to http://dev.jquery.com/newticket. If there is any update, I will post it on my blog.
【中文摘要】
明明在趕程式,被這個Bug絆住,又跟它耗了大半天。利用clone()的寫法在DIV中動態新增Table object,卻發現明明放了4個,children().length卻只傳回3,但這問題只發生在IE上,Firefox上是正常的。研究了一下,發現clone()在IE下會產生額外的Attribute識別,而使用table=table.clone()的寫法,會讓這些識別Attribute變成null,在算個數時就會被過濾掉,看來是jQuery.clone()的Bug,暫無氣力追進去修改,但我先把它Submit反應出去,如果有消息再跟大家說吧。
-
Stopwatch.ElapsedTicks的祕密
-
這次的程式魔人賽,在先前的範例中,用的是Stopwatch.ElapsedTicks做為計數單位。
發現一件好玩的事,我在自己的機器上用DummyPlayer來跑,每一次就算胡亂猜也要近1,000 Ticks。但我接到一組參考數字,DummyPlayer在Q9300上跑,每次大約10-20 Ticks!!
不會吧?? Q6600輸Q9300這麼多?? 接著,更扯的事出現了,另一組DummyPlayer在PentiumD 920上的測試數據,Ticks數也不到100,我的Q6600是中了詛咒嗎?
這讓我想起之前研究過Thread.Sleep精確度的問題,大概有個結論是,計時的精確度與主機板、BIOS、OS有關係。再一查證,Q9300與PentiumD 930用的都是Asus的主機板,加上用Stopwatch計算int i=1做一次跟做10次的ElapsedTicks差不多,大概就有了初步推論(後來證實是錯的),這是不同硬體下造成的精準度的差異,而Asus的主機測量的Tick精確度較高。
會做出以上的推論,是基於一個錯誤的假設: 一個Tick代表的時間長度放諸四海皆同(誤)。
Google到Stopwatch.Frequency的MSDN文件,終於真相大白: 一個Ticks代表的時間長度會隨著硬體不同而有差異。例如我們可以用以下的Code在不同機器上做比較。
using System;
using System.IO;
using System.Threading;
using System.Diagnostics;
public class CSharpLab
{ public static void Test()
{ Stopwatch sw = new Stopwatch();
sw.Start();
int k = 0;
sw.Stop();
Console.WriteLine("Ticks={0:N0}", sw.ElapsedTicks); Console.WriteLine("Freq={0:N0}", Stopwatch.Frequency); decimal ns = 1000000000M / Stopwatch.Frequency;
Console.WriteLine("1 Tick = {0:N4}ns", ns); }
}
測試結果,我的Q6600工作機Freq=2,400,730,000(太約就是2.4Ghz,等於Q6600的CPU內頻),而Asus主板上測得Freq=3,579,545,相差了670倍,也就是說,在我的旗艦上,1 Tick = 0.4165 ns,Asus主板則為 1 Tick = 279.3651ns。如果換算回ms,則1200 Ticks與20 Ticks的時間長度就不會相去太遠。
經過了這番探索,得到了新結論:
- 不同硬體上,每個Tick代表的時間長度可能不同
- 每秒Tick數的極限應該就是CPU的內頻大小 (不過可測出的最小時間間隔也要好幾百Ticks)
- 測試結果比對時,Asus主板的Tick數少,反而是因為其Tick精確度較低所致(跟原來猜想的剛好相反)