[JS] DOM and DOM manipulations
DOM 文件物件模型
:DOM 是 HTML,XML, SVG 文件的程式介面,他把文件跟程式語言(ex, js)綁在一起。透過 DOM,我們可以用 JS 來操控 HTML.
“It is an abstract representation of structured text, where the structured text is our HTML code.”
DOM manipulation
DOM manipulation 是很耗費性能的!
Why?
TL;DR: 因為 DOM 在 browser 中的操作所造成的 reflow(計算 render tree layout), repaint(計算 render tree 順序)很消耗性能。
這是 Webkit 處理 HTML,Css 的流程。
webkit(owned by apple) 是一個 open source 的 rendering engine,被應用在 chrome, safari 等等。
所有在 ios device 的瀏覽器都是用 webkit engine,因為 apple 不讓其他 engine 在 ios 中被使用。 https://www.quora.com/Whats-the-browser-engine-of-Chrome-in-an-iOS-device
當 server 在接收到 browser 所收到的請求後,會傳送 HTML/Css 給 browser,並且會發生以下幾件事:
- 首先,rendering engine 會編譯(parse)HTML 和 Css 用瀏覽器提供的各自編譯器(parser),HTML 會被建構出巢狀的 Js 物件稱為 Node Tree (DOM tree),CSS 則會被架構出巢狀的 CSSOM(CSS object Modal or CSSOM tree)。
- 接下來,rendering engine 會把 DOM tree 和 CSSOM tree 結合成 Render tree。
以上兩步驟完成後,就會進入渲染流程,會有以下幾個步驟:
Reflow or Layout stage(排版)階段
- 瀏覽器首先會為 render tree 中的各個節點建構排版,這包含了計算每個節點在螢幕上的像素尺存以及確切的位置(positions and the coordinates),透過從 Node 的源頭(root node)開始往下計算每個 element 和其附近的 element 的位置跟關係(ex, 確切距離 exact pixels)。我們將這個過程為 layout(排版),這個過程又被稱作 reflow 或是 browser reflow。要注意的是當我們在捲動螢幕、調整視窗大小或是修改 DOM 元素時,都會觸發 layout 的程序。
這是一個很消耗性能的步驟,因為他要從頭到尾計算每個 node 之間的距離跟關係。
- 瀏覽器首先會為 render tree 中的各個節點建構排版,這包含了計算每個節點在螢幕上的像素尺存以及確切的位置(positions and the coordinates),透過從 Node 的源頭(root node)開始往下計算每個 element 和其附近的 element 的位置跟關係(ex, 確切距離 exact pixels)。我們將這個過程為 layout(排版),這個過程又被稱作 reflow 或是 browser reflow。要注意的是當我們在捲動螢幕、調整視窗大小或是修改 DOM 元素時,都會觸發 layout 的程序。
Painting/ repaint (繪圖)階段
- 在這個階段,排版完的 render tree 有可能會有元素互相重疊(ex, z-index),透過 painting 這個階段把各個元素的 painting 上下等等順序計算好(ex, background first, then text, then rectangle)。
Compositing (組合)階段 在 compositing(組合)階段時,rendering engine 才會會透過 GPU 被繪製到螢幕中。
怎麼減少 reflow & repaint?
- 用 transform 的 translate 來代替剛改 position 的 top/left 更改位置
- 如果知道會用到 transform 的話,預先用
will-change:transform
語法來預先告知瀏覽器做準備 - CSS 樣式儘量批量修改
- 避免使用 table 佈局(因為 table 節點改變都會造成重新 reflow)
- 為元素提前設置好高寬,不因多次渲染改變位置
DOM tree
CSSOM tree
DOM traversal
額外補充
CSS 到底會不會阻塞頁面渲染?
- DOM 解析和 CSS 解析是兩個並行的進程,所以這也解釋了為什麼 CSS 加載不會阻塞 DOM 的解析(parsing)。
- 然而,由於 Render Tree 是依賴於 DOM Tree 和 CSSOM Tree 的,所以他必須等待到 CSSOM Tree 構建完成,也就是 CSS 資源加載完成(或者 CSS 資源加載失敗)後,才能開始渲染。因此,CSS 加載是會阻塞 Dom 的渲染 (rendering)的。
- 由於 js 可能會操作之前的 Dom 節點和 css 樣式,因此瀏覽器會維持 html 中 css 和 js 的順序。因此,樣式表會在後面的 js 執行前先加載執行完畢。所以 css 會阻塞後面 js 的執行。
資料來源:
https://cloud.tencent.com/developer/article/1819747
https://zellwk.com/blog/dom-traversals/
https://medium.com/technogise/dom-manipulation-in-browser-59b793bee559
https://medium.someone.tw/web-%E7%80%8F%E8%A6%BD%E5%99%A8%E5%A6%82%E4%BD%95%E7%B9%AA%E8%A3%BD%E7%B6%B2%E9%A0%81-%E6%8E%A2%E8%A8%8E-dom-cssom-%E8%88%87%E6%B8%B2%E6%9F%93-%E7%BF%BB%E8%AD%AF-e9ba8c2be451
https://medium.com/walkout/%E5%A2%9E%E9%80%B2%E6%95%88%E8%83%BD%E5%BE%9E%E4%BA%86%E8%A7%A3%E7%80%8F%E8%A6%BD%E5%99%A8%E9%96%8B%E5%A7%8B-%E9%97%9C%E9%8D%B5%E6%B8%B2%E6%9F%93%E8%B7%AF%E5%BE%91-595c5da265a9
https://stackoverflow.com/questions/34269416/when-does-parsing-html-dom-tree-happen
https://developer.chrome.com/blog/inside-browser-part3/
https://zhuanlan.zhihu.com/p/86153264