iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 26
0
Modern Web

VueJS 從前端到後端系列 第 26

大型資料載入實例與狀況 Event Binding Day 25

部落格同步刊登 [IT 鐵人賽] 大型資料載入實例與狀況 Event Binding Day 25

今天跟大家聊一下關於大型資料的一些例子。先說在最前面的,這種案例其實不多,屬於 八奇 系列。

一般來說,我們在 API 能拿到的 JSON 你覺得該有多大?


大量資料的渲染問題

實際上我拿過最大的 JSON 大概是 20MB,這是什麼概念呢?想像一下你需要在前端一口氣渲染超過 2000 個 DOM 元件,在這種情況下,如果你的前端裝置效能不好的話,那麼你可能就會卡在畫面上等了好久才會有東西出現。

對於 JavaScript 來說,單純的使用 for 迴圈,從 1 數到 2000 的話,你覺得大概需要多久?以我的 2012 年的 Macbook Pro 用 Chrome 來跑,單純的插入一個純文字的 <p>,大概是 65 ms 上下。這是以純文字的方式來處理,所得到的數字。

今天,當你的對象是比較複雜的 DOM 的話,那麼這個數字就可能會來到相當可怕的等級。舉例來說,我一樣是渲染 2000 個 DOM,然後將每個 DOM 都綁上了一個 click 事件,那麼,在 Vue 裡面,他的渲染過程就會延遲到 3 ~ 5 秒的等級。以我的電腦來說,大概被放大了 5 ~ 10 倍左右。


所以,面對這種比較奇怪的需求,我們該怎麼處理?通常來說,有幾種解法:

  • 不要用框架。
  • 用 Canvas 處理畫面。
  • 用 Vanilla JS 處理事件。

以單一事件的綁定需求來說,如果同時要在 2000 個元件綁定一個事件,那麼我們可以換個角度來思考,可能我們比較原始的作法是這樣:

<div id="container">
    <span @click.prevent="doSomething($event)">...</span>
    // 中略 ... 這邊放了 2000 個 span
</div>

那麼,我們可以把這個事件往外放:

<div id="container" @click.prevent="doSomething($event)">
    <span>...</span>
    // 中略 ... 這邊放了 2000 個 span
</div>

這麼做可以省下 綁定了 2000 次 這件事情,最終只會綁定一次事件而已。但是,這麼做你的事件對象就會改變,你必須要自己處理事件對象的相關判斷,換句話說,你原本的 $event.target 可能會是 <span> ,當你往上提的時候,他有可能會是 <div> 也有可能是 <span> ,當然也會有可能是 #text 節點。

所以,扣除掉 事件對象 這件事情比較麻煩以外,只綁定一次,跟綁定了 2000 次比起來,就能省下不少 JavaScript 在處理的時間。其實無論是何種框架,當你的虛擬節點( Visual DOM )需要處理這麼大量的資訊時,所耗費的時間是相當可觀的。


原生的好

https://ithelp.ithome.com.tw/upload/images/20190927/20001433KQYBcFOtl1.png

雖然說原生的 JavaScript 用於處理 DOM 上面相對吃力,不過處理的好的話,基本上並不會影響到你所使用的框架。畢竟,你的框架不也都來自于源生的 JavaScript (誰沒有父母啊)。

但是,你也能把原生的寫得很爛就是了(這一點就不討論了)。

面對這種大量畫面產生的需求,另外一個面向是使用 字串 來處理。也就是說,你可以把 2000 個 <span> 當作字串,最後用 innerHTML 把他放到 DOM 結構樹裡面。也就是說,你可以不用每次都 document.createElement('span') 這樣做事。缺點就是那個字串可能會比你當初拿到的 JSON 還要更肥大就是。

但,純粹的組合字串一直都是相當快速的事情。

至於你說 Canvas ,因為我不太熟悉,所以跳過(欸)。


小結

基本上就是跳脫思考慣性,如果綁一次就可以解決,那麼為何一定要綁 2000 次呢?由於資料的關係所以我也不方便舉太多例子(笑)。


上一篇
動態載入 webpack 簡易設定 Day 24
下一篇
大型資料載入實例與狀況 Large of DOMs Day 26
系列文
VueJS 從前端到後端31

尚未有邦友留言

立即登入留言