用 setInterval 防止瀏覽器卡死

Twitter 上面的 vincicat 發問

@timdream 咦,這個沒聽過,setInterval是怎樣避免block UI?

其實這個技巧我已經忘記是哪裡看到,還是小時候自己試出來的。總之,如果要重複進行一個會讓瀏覽器卡住的計算或是 DOM Operation,可以考慮不要用原本的 forEach、for、或是 while,改用以下的 pattern。

原本的:


arr.forEach(
    function (val, key) {
        [昂貴 DOM 運算,例如畫 canvas,塞 element ...]
    }
);

可以換成


var i = arr.length-1;
timer = setInterval(
    function goNext() {
        [昂貴 DOM 運算,例如畫 canvas,塞 element ...]
        if (!i--) {
            clearTimeout(timer);
        }
    },
    0
);

或是,如果在意順序的話:


var i = 0;
timer = setInterval(
    function goNext() {
        if (i >= arr.length) {
            clearTimeout(timer);
            return;
        }
        [昂貴 DOM 運算,例如畫 canvas,塞 element ...]
        i++;
    },
    0
);

因為瀏覽器的 UI 是 single thread queue,在網頁的 Javascript 執行完之前瀏覽器是沒有辦法做其他事的。不過用了這個 pattern,我的猜想是即便程式碼是 0 ms 的 setInterval,在迴圈兩個元素執行之間瀏覽器會有機會 queue 自己的工作,因此 UI 可以保持有回應的狀態(例如,使用者可以按 Ctrl+F5 reload)。

當然真的需要花時間的計算要丟進 Web Workers 才對啦,但我自己的經驗是有支援 Web Workers 的瀏覽器速度都夠快 … 根本就用不到 Web Workers。而且真正會卡的東西都是 DOM Operation,Web Workers 不能用。雖說整個迴圈執行的總時間會加長,但是體驗上比較 OK;瀏覽器把每個步驟的 DOM 改變都呈現出來有時會有意想不到的視覺效果 :)。

這是最近寫某個玩具的心得,stay tuned for announcement。

WordPress Subversion Install/Upgrade Script

不值得大張旗鼓的小東西,不過既然貼出來了就介紹一下。

wp-script:WordPress 安裝/升級用 shell script

以前就用 shell script 管 WordPress 的安裝與升級,不過後來發現這樣用蓋 tarball 的方式放檔案會讓舊檔案一直被留在機器裡。所以後來就直接拉 WordPress 的 subversion 程式庫裡的檔案跑 svn switch,直接跳到需要的版本的 tag。這組 script 又額外加上了和 API 溝通,直接問 WordPress.org 最新的版號,所以執行起來又更方便。建議的使用情境是看到 WordPress 有更新的新聞就連進去執行備份+更新。不建議在不做自動備份的情況用 crontab 自動更新。

至於中文檔案的部分,script 加上了 subversion 的 external reference ,會去抓 Kirin_Lin 維護的 WordPress 中文翻譯(放在 automattic 那邊)。不過,他有時候無法在緊急更新的時候把版號 tag 即時 commit 到中文程式庫(有時候也沒有必要,因為介面沒有修改),這個時候 script 找不到該版號的目錄就會去抓 trunk。

用文字描述程式行為有點難懂,歡迎直接去看 source code =) 接下來應該會寫幾個單鍵更新外掛和佈景的 script 放進去,一樣也是會自動查版號。

CSS3 與 Javascript 東亞文字直排

因為工作的關係,最近在研究在 Web 上面直排中文的實作。在這裡整理一下最近的發展。

Webkit CSS3 直排實作

CSS Writing mode module level 3 經過編輯的整理,已經有了一份可以實作的草稿,供瀏覽器支援 CSS3 的直行排版。Webkit 最近在 Nightly 實作了這些 CSS3 propertiy;因為是實驗性質,所以有加上了 -webkit- 前綴。

overflow: 超出邊界了 左邊看不到

此範例是 freedom 所製作。根據他的整理,Webkit 現在的實作還有一點小問題,像是 flow 和捲軸會破版等等。另外現有的實作也不是跨平台的,我自己是試了 Mac 版的 Webkit Nightly,其他平台的 code 好像還沒進去?

另外一件事情是標點符號的處理:直排文字的標點符號要不要旋轉,旋轉要直接轉 glyph,還是字型有同字碼專門給直排用的 glyph;日文、簡中的標點位置和繁體中文又不同也有特別的處理方式。這個因為我不了解實作的手法,所以就不贅述了。

Javascript 直書 Hack

當然在瀏覽器還沒完全支援之前,該做完的事情還是要想辦法湊出來。用 Javascript 排出直排文字的 library 有兩個,一個是 Nehan (涅槃),另一個是 Taketori JS (竹取 JS)

涅槃比較算是硬幹的排版程式;Nehan 2 要求需要直排的文字放進 <pre>,HTML 拿來 inspect 發現 Javascript 會把文字排進表格 …。另外他也發明了一些 tag 來表達排版需求(例如「<indent>」)因為這些設計會打破 HTML 的語意所以後來就不研究這個程式了。

竹取 JS 相較來說就沒有上面的問題:程式會用 CSS 的 transform 把整個 block 轉 +90 度,然後偵測裡面的漢字一個一個用 <span> 包起來轉 -90 度,處理斷行歸則與標點等等。當初發現它的手法的時候覺得超奸詐的;因為這樣用可以處理幾乎所有 HTML 的排版,像是表格、margin、padding 等等。呈現的結果相當優秀,開發商 cmonos 當初會開發竹取 JS 也是用在他們所謂「支援直排文字的 CMS」上,也有實際的網站例子(看這餐廳超有 fu 的 Menu 啊

竹取 JS 也提供 bookmarklet 可以把任何網站變成直行…… 效果怎麼樣就大家自己去玩吧(電腦玩物有寫一篇介紹的文章

前述在標點符號和字型選擇的部分因為只有針對日文字型做處理,我就把 fork 出來把該改的東西加進去了。之前在 Twitter 上面提到竹取的時候竟然就被在京都的原開發者回了話。來回對話之後,對方很好心的把 zip 包放上 Github 讓我可以直接 clone 跟 fork,另外也說了竹取的目標是提供 CSS3 瀏覽器支援之前的「暫時解」。這跟我們這邊想要努力的方向是相同的……希望有一天可以直接把 <script> 拿掉加上兩行 CSS 然後得到相同的結果。

W3C HTML5 Chinese Interest Group

如果您對接下來的發展有興趣的話,歡迎加入 W3C 的 HTML5 中文興趣小組;這裡有簡繁中文與英文的討論,主要的議題就是環繞在直排、中文序數、標音等等中文與東亞語言的議題,還有 HTML5 一般性的討論。

說到中文排版,在網路上問了一些懂出版的朋友,發現一個很尷尬的事情:日文的斷行規則是是 JIS X 4051 日本國家標準;在台灣,規則是各家出版社各個編輯口耳相傳的「習慣」。在 Wikipedia 上,排版斷行規則的文章也只有日文版韓文版英文版就是沒有中文版。技術上,業界也不會遇到真正有動機去影響直排實作網路標準的廠商。是說就排版規則這件事情,JIS 標準絕對夠用(除了注音符號聲符的排版),繁體中文使用者只要站在日文使用者後面增加氣勢(?)就好,但是我們可以搞到這樣,應該有一些需要反省的原因吧。