@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。