JavaScript 的一些效率問題

前幾天在測試each和 for 迴圈的效率時,意外的一直得到 each 效率比較好的奇怪現象,搞了兩天才找到原因。

each 這種方法效率會比 for 迴圈還要低主要是因為它是把要做的事情用 function 傳進去,多了一個 function call 和一層 function scope,要對變數作存取時會多了到不同層 scope 尋找的差,所以理論上它會比 for 迴圈還要慢。除此之外,DOM 本身就很慢了,當然DOM NodeList的操作和存取也不會快到哪去,所以像Sizzle引擎就會把 DOM NodeList 轉成陣列再傳回來,而我測試 each 和 for 兩者的效率時,也就是這個部分產生了非預想的結果,根據測試結果 Google V8 和 Firefox 3.6 的 Tracemonkey 這兩個會編譯 JS 的引擎,第二次對同樣內容的 DOM collection 轉陣列的動作時會比第一次還要快,而且大約是兩倍快,測試的基準是第一次用getElementsByTagName抓 <span> ,第二次用 jQuery,內部也是一樣用 getElementsByTagName ,並且小修改過 DOM 結構後再做一樣的事情也是會比第一次還快,並且,不管是用slice還是 for 迴圈一個元素一個元素推到陣列裡面都沒差很多,一開始因為測試都是對同樣的標籤作處理,結果先測的方法就佔了劣勢,就像是美食漫畫一樣,先上菜的都會輸一樣,不過我對編譯器的怎樣做最佳化的方法不熟,所以這兩個引擎是怎麼辦到的就不清楚了。

除了這點之外,還有一些不算小發現的小發現,第一個就是 Firefox 3.6 還是好慢,詳細數據我忘了,不過和 V8、Safari 比起來差距還是不小,然後就是 IE 超.級.慢!!第二是 each 真的比較慢,不過在現在 JS 引擎普遍暴力的情況下差距其實不明顯(不過 NodeList 和陣列的差距還是有)。第三是前面已經講過的 Sizzle 回傳的是陣列而不是 NodeList ,雖然實際上想要自己組合 NodeList 似乎也是不可能的。最後是 jQeury 可以用$("span")[0]這種寫法來直接存取 DOM 節點,不過它並不是陣列,要轉成純陣列可以用$("span").get(),只是測試過後發現沒有比較快,因為還要重新轉一次陣列,這裡損失的時間也不會比直接存取來的少。


為什麼有 <img> 這個標籤

dive into mark在去年11月有一篇文章Why do we have an IMG element?,裡面翻出了很多當初 HTML 剛起步時的討論,當時就在針對網頁上的媒體內容要怎樣放進去作了不少爭論,過程有興趣的可以自己去看,結果還是先下手為強,先做出來的贏, mark 歸納出的幾點結論中有一點蠻有趣的:「HTML一直都是瀏覽器製造者、標準制定者、網頁製造者和其他想參與其中的人所討論而得的,而多數成功的標準都是 retro-specs (實作、制定標準同時,甚至先實作),有些人認為標準應該保持純潔,不要受到瀏覽器製造者或網頁製造者的影響,這完全是錯誤的。」HTML 5 也是一個 retro-specs ,新功能都是跟著網路的變化所產生,像是拖拉 API近端儲存系統等,最近還多了device 標籤stream API,這些都是現在大家需要的功能,而目前只能用其他方法弄起來,像是拖拉要去算位置、範圍,近端儲存要裝像 Google Gears 的外掛,要抓 webcam 畫面或是撥影片則要用 Flash 或是 Java,未來這些功能都會變成瀏覽器原生支援,甚至用顯示卡加速畫 3D 圖形都不是問題。

另外可以拿來作反例的我覺得是XML Schema,整個複雜過頭,還有難解的用詞,據之前修課時的老師說是語言學家制定的,結果造成沒有工具很難寫,就算寫了沒驗證過我看也不敢拿來用。


Perl Style RegExp for Vim

今天下午在尋找能讓 Vim 的 Regular Expression 變得好看一點的方法,因為實在太多斜線了,當然直接就把目標鎖定在 perl 的語法,一開始找到一個vim tip有建議用perldo,不過編譯時要把+perl弄起來,使用上也不是很好用,而且不能搜尋,只能做取代,雖然有人寫了 function來搜尋,不過實際測試之後離方便使用還有些距離。c9s還有建議我用very magic看看,結果還是不夠滿意,後來換成找日本那邊,終於找到eregex.vim這個 plugin ,他的作法是把 perl/ruby 的 regexp 語法用 function 轉成 vim 的 regexp 語法,所以問題少很多,預設會把 S(大寫S)替換成用 perl/ruby 的 regexp 語法來搜尋搜尋取代的指令,使用方法和原來 s(小寫S)的都一樣,另外單純搜尋的部分有 :M/ 這個命令,也可以 map 到原來的 / 上:

nnoremap / :M/

使用上就和原來幾乎完全一樣了,超棒的~

順帶一提,Ubuntu上要編譯出 +perl 的功能要確定一下 libperl.so 在不在,像我的系統就只有 libperl.so.5.8,還要自己做個鏈結。

由於作者聯絡不上,我已經接起eregex.vim的維護工作了,放在 github 上。


Screen 下 Vim F1~F4 沒辦法正常 map

剛剛遇到的問題,好像是我的環境才會,不過如果有遇到的話就把下面這段 code 加到 vimrc 裡面吧,記得放在 map 前。

" Screen fix
if &term =~ '^screen'
    set t_k1=^[[11~
    set t_k2=^[[12~
    set t_k3=^[[13~
    set t_k4=^[[14~
endif

用 :wq 送出 BBS 文章

因為在 BBS 想要用 :wq 發文章的次數不算少,剛剛就用 expect 弄起來了,只要加一行到 interact 裡面就可以:

\033:wq\r { send \030; send "\r" }

實際操作是要 <ESC> :wq <ENTER> ,會直接把文章發表,如果不想跳過發文前的確認選單,那就把最後的 \r 拿掉。


在 screen windows 裡開一個比較小的 terminal

這真是超特殊的需求,不過今天還是弄出來了,花不少間走錯方向就是,會有這樣的需求是因為我同時要掛 BBS IRC,BBS 的標準視窗大小是 80*24,但是這個大小對於 IRC 來說又太小了,好在現在很多 BBS 系統已經已經支援大於 80*24 的終端機了,但是有一個bahamut自從商業化後 BBS 系統就完全沒改進,不支援就算了,終端機大小只要不對,看文章往下卷頁時就會有錯誤排版產生,最常見就是按 ,本來應該是整個畫面移動一行,結果會變成只有最後一行被取代,而我現在是使用 100*35 的大小,本來是一直把這問題放著,不過今天總算解決了,其實解法很簡單,就是 screen 裡面再開一個 screen,用不同的設定檔案,裡面要拿來上 bahamut 那個的設定檔加上:

width -d 80 24

重點在那個-d參數,本來一直在終端機的設定上跑來跑去,不是說沒辦法改大小,就是內部的終端機改大小會影響到外面的,版面就整個亂掉,不過 -d 是只改 display 的大小,不是終端機大小,本來的話是會所有的 screen 一起改,但是因為用兩層的關係,所以外面的不會受到影響。


新年快樂

新年快樂!

今年因為腳包著石膏,所以三天假期都沒出門,31號回到家後就等著看紅白,這是我第一次有從一開始就看到啊,話說我每年12/31都會想著明年一定要裝BSD,然後一年一年一直過去....,算了,等電視升級時在一起好了。今年紅白有水樹奈奈登場,對我來說算是比較有特別意義,到不是特別迷她,而是史上第一位聲優登上紅白,總覺得要見證一下,加上今年是第 60 屆,感覺就是不能錯過~~

話說這三天我竟然沒有很墮落的睡覺看動畫,第一天整理了 irc logs,把部落格內的文章又掃過一次,檢查有沒有圖片連結錯誤,然後重新編譯了我機器上的vim,之前忘了 patch ,加上沒把gettext功能弄上,所以介面一直是中文的,另外就是搞定了tcsh的 Home,、End、PageUp 等案件的功能,因為和bash用 inputrc 的設定不一樣,一直到這天才找到設定方法, bash 下的 inputrc 是這樣寫:

"\e[1~": beginning-of-line
"\e[2~": yank
"\e[3~": delete-char
"\e[4~": end-of-line
"\e[5~": history-search-backward
"\e[6~": history-search-forward

tcsh 則是寫在 cshrc 裡面:

bindkey "\e[1~" beginning-of-line
bindkey "\e[2~" overwrite-mode
bindkey "\e[3~" delete-char
bindkey "\e[4~" end-of-line
bindkey "\e[5~" history-search-backward
bindkey "\e[6~" history-search-forward

第三天玩的 zsh 也和 tcsh 一樣。

第二天都在看 javascript 的文章影片,其中有一篇Rendering: repaint, reflow/relayout, restyle蠻不錯的,介紹了 render tree 的概念,是以前沒接觸過的,另外還看了不少 performance 相關的文章,希望 Nicolas 的High Performance JavaScript能快點出。

第三天早上則是弄拖了很久的Opera 三太子Mac 版,因為這部份動力不大所以一直都沒什麼動,不過這次算是蠻有進度的,幾乎大部分的設定都有套上去了,該改的檔案要放哪也大概都確定了,應該過陣子會有個測試版吧,接著因為噗浪上zsh正夯,所以我也玩起來了,zsh 是真的厲害不少,自動完成的功能,git 後面的指令也會自動完成,還會列出參考,cd 可以直接切換父層目錄,例如要從 「xx/2.1/blah/blah/blah」 跑到 「xx/2.2/blah/blah/blah」 只要輸入 cd 2.1 2.2 就可以了,另外我發現他除了PROMPT可以設定外,還有一個RPROMPT,是會放在最右邊的,而且指令打太長時還會自動消失,不過因為在 freebsd 下設定顏色的方法找很久才找到,所以整個幾乎下午剩下的時間都在弄,我的 zsh 現在變這樣了。

zsh

最後就是今天晚上開始用github備份我的rc 檔了,現在比較整齊的只有 zshrc 吧XD。

至於動畫,不知道為什麼把大運動會OVA 版重看一遍了,其實 TV 版也在重看,只是 OVA 比較好看,TV 最後面太超展開了,所以越看越慢,日本年假期間都沒新動畫啊><。


➡ 前一個月的文章