面試官常常會問你:「平時工做中,你怎麼優化本身應用的性能?」
你回答以下:「我平時遵循如下幾條原則來優化個人項目、以提升性能,主要有:」javascript
a. 減小DOM操做的次數(減小DOM的獲取與修改次數)css
b. 減小網絡請求html
c. 壓縮、合併靜態資源文件(css、js、img等)前端
d. 小圖片文件base64化處理vue
e. js少用全局變量java
f. ...web
Bingo!此時,你給本身刨了個能夠把本身埋住的大坑。
由於面試官可能會追問你:「爲何減小DOM操做能夠提升性能?」面試
爲何呢?
_______chrome
DOM
就是Document Object Model
,文檔對象模型,裏邊是接口,即方法函數。咱們經過調用並傳指定參數來使用。
官方定義:DOM是一個獨立於語言的、用於操做XML和HTML文檔的程序接口(API)。在瀏覽器中主要用於與HTML文檔打交道,而且使用DOM API用來訪問文檔中的數據。
DOM是個與ES語言無關的API,它在瀏覽器中的接口倒是用JavaScript來實現的,DOM就成了如今JS編碼中的重要部分。瀏覽器
瀏覽器 | JS位置 | DOM位置 |
---|---|---|
IE | JavaScript的實現名爲JScript,位於jscript.dll文件中 | DOM的實現則存在另外一個庫中,名爲mshtml.dll(內部稱爲trident) |
safari | JavaScript部分是由獨立的SquirelFish引擎來實現。 | DOM和渲染是使用webkit中的webcore實現 |
google chrome | JavaScript引擎是他們本身研發的,名爲V8。 | 使用webkit中的webCore庫來渲染頁面 |
firefox | JavaScript引擎名爲TraceMonkey | 渲染引擎Gecko |
ES經過DOM接口來獲取文檔中的元素。
正由於瀏覽器中一般把DOM和ECMAScript獨立實現。使得兩者相互獨立,就像兩座孤島。
因此ES每次操做DOM時,ES和DOM之間就像兩個橋之間須要過車輛。
每次連接就都須要搭建一個橋樑,搭橋仍是小事,ES請求DOM的車輛過橋時,會通過一個收費站,每次都會被收費。JS引擎會消耗瀏覽器的性能進行繳費。
而車輛經過後橋就銷燬,下次連接從新搭橋二次繳費。因此說JS與DOM每次鏈接都須要消耗性能 。
也正所以,有了每操做一次DOM就多作點事的理念,儘量以最少的次數處理最多的DOM操做,以實現每過一次橋多拉點貨的效果。
(VUE也正是這種理念,操做虛擬dom減小性能消耗,所以vue性能更優,另個話題來講。)
正由於兩者相互獨立,因此每次連接、每次訪問DOM都會消耗性能!! 能夠說操做dom是十分昂貴的!!寧肯處理一萬次js,也不操做一次dom!!
像上邊說的,每次操做DOM以前,就會先訪問DOM,因此也會消耗性能。
在此基礎上,由於修改DOM會致使瀏覽器從新計算頁面的幾何變化、引起瀏覽器模板引擎的重排(迴流 - 回滾流程)和重繪,進而更加消耗性能。
瀏覽器下載完頁面中的全部資源(好比HTML、JavaScript、CSS、圖片等)後,會發生以下的6步過程:
先看一張圖:
由上圖得知以下流程:
不可見節點: 不會渲染輸出的節點(不會顯示在屏幕上的節點)有如下幾種
當DOM的變化影響了元素的幾何屬性(寬和高),瀏覽器須要從新計算元素的幾何屬性,一樣其餘相鄰元素的幾何屬性和位置也會所以受到影響。瀏覽器會使渲染樹中受到影響的部分失效,並從新構造渲染樹。這個過程稱爲「重排」。
換句話說,改變了頁面中某元素的位置、尺寸大小,進而也就改變了他的佔地面積。那這個元素修改了佔地面積後,其後緊鄰的元素就得挪動位置。給她讓地兒(或者向前趕趕)。緊鄰的元素挪動了,那緊鄰元素後邊的元素也會連鎖效應式的修改。這就比如一排人排隊。前邊的人忽然變胖了、變瘦了、向前挪了、向後擠了、都會致使隊伍中後邊的人也跟隨之改變位置,由此致使一連串的人都挪動位置。這時瀏覽器就要從新排版各個受到影響的元素的位置。反應在渲染引擎的工做流程中也就是瀏覽器須要從新計算元素位置信息並佈局render樹。這就是重排。
完成重排後,瀏覽器會從新繪製受影響的部分到屏幕中,該過程稱爲重繪。
由於重排在重繪的上一步,因此重排發生後天然會致使重繪。這個很好理解。
當頁面佈局和幾何屬性改變時就須要重排:
(核心就是:只要某個屬性能致使位置信息發生改變,就會觸發重排 )
試驗:resize視口,一個頁面中div元素的位置不受視口調整而修改,也會引起重排
現代瀏覽器是至關完善的了,由於屢次操做DOM會觸發重排重繪、消耗性能。因此除了咱們人爲的、有意識的去控制操做DOM次數之外,瀏覽器在設計上進行了優化,也會智能的「節流」操做DOM,好比實現隊列化修改、批量執行。
解釋來講就是,瀏覽器會有一個「隊列」,用以存放(攢着)須要操做DOM的js程序。每當執行一次js操做dom的代碼,這個隊列裏就先暫存一個程序。等到一段時間後,瀏覽器再集中、批量的連接一次"ES島"和"DOM島"(就是讓JS引擎去連接渲染引擎),進而觸發一次DOM操做。你能夠形象的理解爲「過一段時間發一班車」。
可是咱們人類感知不到啊,可能會由於誤操做打斷瀏覽器的「節流」步驟。迫使瀏覽器中斷當前的「等待」,去趕忙、立馬進行一次dom操做。讓瀏覽器趕忙執行完他攢在「隊列」裏的JS操做DOM的程序後返回最新的DOM位置信息給咱們。這就好像電梯門定時自動關閉,可是你卻手動按了關門按鈕強迫關門同樣。
這種狀況就發生在咱們獲取DOM信息的時候:
打斷瀏覽器優化,強迫觸發重排的屬性:
offsetTop、offsetLeft、offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
getComputedStyle()
由於要跟瀏覽器請求最新的DOM信息,因此瀏覽器就得趕忙讓JS引擎去渲染引擎那裏進行一次DOM操做。
試驗gif圖:
(想到一個驗證只發生重繪的狀況,那就是後邊也加點元素,若是重排了,後邊的元素在控制檯的檢測下也會閃綠光。)
既然知道了這個dom操做會觸發重排、重繪。那又是爲何要儘可能避免重排和重繪呢?
換句話說,重排和重繪的反作用是什麼?缺點是什麼?
這就要引入CPU和GPU了。
重排會佔用CPU,dom元素位置計算會消耗CPU的算力,因此應該儘可能減小CPU的佔用,使電腦不卡頓。
重繪會佔用GPU,渲染頁面時會消耗GPU的算力。
GPU的分類:
DOM操做基本就是畫圖形的,但瀏覽器中用的就是家用GPU,其畫圖形耗費的性能是專業GPU的幾十倍。因此不提倡頻繁用裝有家用GPU的瀏覽器繪製頁面。也就是不提倡頻繁觸發重繪。
由於重排必然會引起重繪,因此在瀏覽器的開發者工具中提供了一個檢測重繪的按鈕。尋找和打開步驟以下圖:
能夠關注個人微信公衆號看更多總結文章~