前端性能優(yōu)化:細(xì)說瀏覽器渲染的重排與重繪

原文鏈接 https://www.imooc.com/article/45936 侵刪

圖片描述

前端性能優(yōu)化因為涉及到計算機網(wǎng)絡(luò)货抄、數(shù)據(jù)算法述召、圖形圖像處理、瀏覽器渲染等多方面計算機知識蟹地,常作為前端工程師樂此不疲的技術(shù)討論話題积暖,也正因如此,它也是面試時容易被問及的面試題之一怪与。

緣起

本篇文章緣起一次偶然的面試問答所引申出的思考整理夺刑,著筆于瀏覽器渲染的角度,探討前端性能優(yōu)化的思路和實踐建議,當(dāng)然遍愿,瀏覽器渲染是一個復(fù)雜的過程存淫,本文筆者將圍繞重排和重繪兩個關(guān)鍵詞開始行文。

目錄結(jié)構(gòu)

文章大致行文思路如下:

  • URL從輸入到頁面展示的過程

  • DOM和JavaScript的關(guān)系

  • 為什么操作DOM會很“慢”

  • 瀏覽器解析HTML的過程

  • 重排

  • 重繪

  • 優(yōu)化方案

URL從輸入到頁面展示的過程

在探討瀏覽器解析html之前沼填,先了解url從輸入到最后頁面渲染的過程是一個很有必要的步驟桅咆,它可以幫助我們把握整體流程,讓我們在了解HTML解析細(xì)節(jié)之前知道它處于整個請求周期中的哪一階段坞笙,這對我們構(gòu)建完善知識圖譜很有幫助岩饼。

首先,我們假設(shè)輸入的url的請求為最簡單的Http請求薛夜,以GET請求為例籍茧,大致分以下幾個步驟:

  1. 用戶在瀏覽器的地址欄輸入訪問的URL地址。瀏覽器會先根據(jù)這個URL查看瀏覽器緩存-系統(tǒng)緩存-路由器緩存梯澜,若緩存中有硕糊,直接跳到第6步操作,若沒有腊徙,則按照下面的步驟進行操作简十。

  2. 瀏覽器根據(jù)輸入的URL地址解析出主機名。

  3. 瀏覽器將主機名轉(zhuǎn)換成服務(wù)器ip地址撬腾。瀏覽器先查找本地DNS緩存列表螟蝙,看緩存里面是否存在這個ip,如果有則進入第4步,如果緩存中不存在這個ip地址民傻,就再向瀏覽器默認(rèn)的DNS服務(wù)器發(fā)送查詢請求胰默,同時緩存當(dāng)前這個ip到DNS緩存列表中。更詳細(xì)步驟參考DNS查找域名的過程漓踢。

  4. 拿到ip地址后牵署,瀏覽器再從URL中解析出端口號。

  5. 拿到ip和端口后喧半,瀏覽器會建立一條與目標(biāo)Web服務(wù)器的TCP連接奴迅,也就是傳說中的三次握手。傳送門:完整的tcp鏈接挺据。

  6. 瀏覽器向服務(wù)器發(fā)送一條HTTP請求報文取具。

  7. 服務(wù)器向瀏覽器返回一條HTTP響應(yīng)報文。

  8. 關(guān)閉連接 瀏覽器解析文檔扁耐。

  9. 如果文檔中有資源則重復(fù)6暇检、7、8動作婉称,直至資源全部加載完畢块仆。

以上步驟簡述了瀏覽器從輸入url到最后頁面呈現(xiàn)的大致過程构蹬,但這并不很具體,比如瀏覽器請求報文類型是什么悔据,會遇到哪些錯誤場景庄敛、瀏覽器又是如何解析響應(yīng)報文等等都沒具體描述。

實際上在http請求方式不同蜜暑、有無代理、有無負(fù)載均衡等不同場景下訪問服務(wù)器的細(xì)節(jié)流程也會有一些差別策肝,但這并不影響我們對整個訪問環(huán)節(jié)的理解肛捍,有興趣的同學(xué)可網(wǎng)上自行詳細(xì)了解,在此不做詳述之众。

DOM和JavaScript的關(guān)系

文檔對象模型(DOM)是一個獨立于語言拙毫,用于操作XML和HTML文檔的API,在web端,我們常用來操作HTML棺禾,但其實DOM也是可以操作XML文檔的缀蹄。

我們現(xiàn)在知道,DOM是一個獨立于語言的API膘婶,換句話說缺前,DOM是一個與語言無關(guān)的API,別的語言也可以實現(xiàn)操作DOM的具體api悬襟,但是它在瀏覽器中是用JavaScript來實現(xiàn)的衅码,也因此,DOM是現(xiàn)在JavaScript編碼中很重要的一部分脊岳,因為JavaScript很多時候都在操作底層文檔逝段。

為什么操作DOM會很慢

雖然DOM是由JavaScript實現(xiàn)的,但是在瀏覽器中都是把DOM和JavaScript分開來實現(xiàn)的割捅,比如IE中奶躯,JavaScript的實現(xiàn)名為JScript,放在jscript.dll文件中亿驾,而DOM則放在另一個叫做mshtml.dll的庫中嘹黔。在Safari中,DOM和渲染是使用Webkit中的WebCore實現(xiàn)莫瞬,而JavaScript是由獨立的JavaScriptCore引擎實現(xiàn)参淹,同樣在Chrome中,同樣是使用WebCore來實現(xiàn)渲染乏悄,而JavaScript引擎則是他們自己研發(fā)的V8引擎浙值。

由于DOM和JavaScript是被分開獨立實現(xiàn)的,因此檩小,每一次在通過js操作DOM的時候开呐,就需要先去連接js和DOM,我們可以這樣理解:把DOM和JavaScript比作兩個島,他們之間通過一個收費的橋連接著筐付,每一次訪問DOM的時候卵惦,就需要經(jīng)過這座橋辆沦,并且給“過路費”然磷,訪問的次數(shù)越多,路費就會越高空凸,并且訪問到DOM后较解,操作具體的DOM還需要給“操作費”畜疾,由于瀏覽器訪問DOM的操作很多,因此印衔,“路費”和“操作費”自然會增加啡捶,這就是為什么操作DOM會很慢的原因

瀏覽器渲染HTML的步驟

HTML渲染大致分為如下幾步:

  1. HTML被HTML解析器解析成DOM Tree, css則被css解析器解析成CSSOM Tree。

  2. DOM Tree和CSSOM Tree解析完成后奸焙,被附加到一起瞎暑,形成渲染樹(Render Tree)。

  3. 節(jié)點信息計算(重排)与帆,這個過程被叫做Layout(Webkit)或者Reflow(Mozilla)了赌。即根據(jù)渲染樹計算每個節(jié)點的幾何信息。

  4. 渲染繪制(重繪)玄糟,這個過程被叫做(Painting 或者 Repaint)揍拆。即根據(jù)計算好的信息繪制整個頁面。

以上4步簡述瀏覽器的一次渲染過程茶凳,理論上嫂拴,每一次的dom更改或者css幾何屬性更改,都會引起一次瀏覽器的重排/重繪過程贮喧,而如果是css的非幾何屬性更改筒狠,則只會引起重繪過程。所以說重排一定會引起重繪箱沦,而重繪不一定會引起重排辩恼。

重排(Relayout/Reflow)

在弄明白什么是重排之前,我們要知道:瀏覽器渲染頁面默認(rèn)采用的是流式布局模型(Flow Based Layout)谓形,這一點很重要灶伊。

所謂重排,實際上是根據(jù)渲染樹中每個渲染對象的信息寒跳,計算出各自渲染對象的幾何信息(DOM對象的位置和尺寸大衅溉),并將其安置在界面中的正確位置童太。

由于瀏覽器渲染界面是基于流式布局模型的米辐,也就是某一個DOM節(jié)點信息更改了胸完,就需要對DOM結(jié)構(gòu)進行重新計算,重新布局界面翘贮,再次引發(fā)回流赊窥,只是這個結(jié)構(gòu)更改程度會決定周邊DOM更改范圍,即全局范圍和局部范圍狸页,全局范圍就是從根節(jié)點html開始對整個渲染樹進行重新布局锨能,例如當(dāng)我們改變了窗口尺寸或方向或者是修改了根元素的尺寸或者字體大小等;而局部布局可以是對渲染樹的某部分或某一個渲染對象進行重新布局芍耘。

在此址遇,總結(jié)會引起重排的操作有:

  1. 頁面首次渲染。

  2. 瀏覽器窗口大小發(fā)生改變齿穗。

  3. 元素尺寸或位置發(fā)生改變傲隶。

  4. 元素內(nèi)容變化(文字?jǐn)?shù)量或圖片大小等等)饺律。

  5. 元素字體大小變化窃页。

  6. 添加或者刪除可見的DOM元素。

  7. 激活CSS偽類(例如::hover)复濒。

  8. 設(shè)置style屬性

  9. 查詢某些屬性或調(diào)用某些方法脖卖。

常見引起重排屬性和方法
width height margin padding
display border position overflow
clientWidth clientHeight clientTop clientLeft
offsetWidth offsetHeight offsetTop offsetLeft
scrollWidth scrollHeight scrollTop scrollLeft
scrollIntoView() scrollTo() getComputedStyle()
getBoundingClientRect() scrollIntoViewIfNeeded()

重排也叫回流,實際上巧颈,reflow的字面意思也是回流畦木,之所以有的叫做重排,也許是因為重排更好理解砸泛,更符合中國人的思維十籍。標(biāo)準(zhǔn)文檔之所以叫做回流(Reflow),是因為瀏覽器渲染是基于“流式布局”的模型,流實際就使我們常說的文檔流唇礁,當(dāng)dom或者css幾何屬性發(fā)生改變的時候勾栗,文檔流會受到波動聯(lián)動的去更改,流就好比一條河里的水盏筐,回流就好比向河里扔了一塊石頭围俘,激起漣漪,然后引起周邊水流受到波及琢融,所以叫做回流界牡,這樣理解似乎更標(biāo)準(zhǔn)更規(guī)范,不過叫什么并不重要漾抬,重要的是我們真正理解了這個過程便好宿亡。

重繪(Repainting)

相比重排,重繪就簡單多了纳令,所謂重繪她混,就是當(dāng)頁面中元素樣式的改變并不影響它在文檔流中的位置時烈钞,例如更改了字體顏色,瀏覽器會將新樣式賦予給元素并重新繪制的過程稱。

常見引起瀏覽器繪制過程的屬性包含:

color border-style visibility background
text-decoration background-image background-position background-repeat
outline-color outline outline-style border-radius
outline-width box-shadow background-size

性能優(yōu)化

我們知道操作DOM是一個高成本的操作坤按,不僅是因為本身js與DOM的鏈接訪問毯欣,還包括操作DOM后悔引起一連串的連鎖反應(yīng)(重排),因此臭脓,從性能優(yōu)化角度酗钞,我們可以從以下幾個方面著手:

  • 減少DOM操作

    • 最小化DOM訪問次數(shù),盡量緩存訪問DOM的樣式信息来累,避免過度觸發(fā)回流砚作。

    • 如果在一個局部方法中需要多次訪問同一個dom,則先暫存它的引用嘹锁。

  • 采用更優(yōu)的API替代消費高的api葫录,轉(zhuǎn)換優(yōu)化消費高的集合

    • 用querySelectorAll()替代getElementByXX()。

    • 開啟動畫的GPU加速领猾,把渲染計算交給GPU米同。

    • 少用HTML集合(類數(shù)組)來遍歷,因為集合遍歷比真數(shù)組遍歷耗費更高摔竿。

    • 用事件委托來減少事件處理器的數(shù)量面粮。

  • 減少重排

    • 避免設(shè)置大量的style屬性,因為通過設(shè)置style屬性改變結(jié)點樣式的話继低,每一次設(shè)置都會觸發(fā)一次reflow熬苍,所以最好是使用class屬性

    • 實現(xiàn)元素的動畫,它的position屬性袁翁,最好是設(shè)為absoulte或fixed柴底,這樣不會影響其他元素的布局

    • 動畫實現(xiàn)的速度的選擇。比如實現(xiàn)一個動畫粱胜,以1個像素為單位移動這樣最平滑柄驻,但是reflow就會過于頻繁,大量消耗CPU資源年柠,如果以3個像素為單位移動則會好很多凿歼。

    • 不要使用table布局,因為table中某個元素旦觸發(fā)了reflow冗恨,那么整個table的元素都會觸發(fā)reflow答憔。那么在不得已使用table的場合,可以設(shè)置table-layout:auto;或者是table-layout:fixed這樣可以讓table一行一行的渲染掀抹,這種做法也是為了限制reflow的影響范圍

  • css及動畫處理

    • 少用css表達式

    • 減少通過JavaScript代碼修改元素樣式虐拓,盡量使用修改class名方式操作樣式或動畫;

    • 動畫盡量使用在絕對定位或固定定位的元素上傲武;

    • 隱藏在屏幕外蓉驹,或在頁面滾動時城榛,盡量停止動畫;

最后總結(jié)

本篇文章主要抓取url從輸入到最后渲染成界面這一流程中的瀏覽器解析渲染HTML這一步驟來探討前端優(yōu)化的思路和原因态兴,核心思想基于重排和重繪的關(guān)系來展開討論狠持,主題大致有如下幾點:

  • url從輸入到最后渲染的大致環(huán)節(jié)。

  • 重排一定會重繪瞻润,重繪不一定有重排喘垂。

  • Js操作DOM是一個高消費過程。

  • 會引起重排/重繪的屬性和方法列舉

  • 優(yōu)化思路(減少dom操作绍撞、替換高性能api正勒、暫存引用、減少重排傻铣、開啟硬件加速等)章贞。

最后,由于個人水平原因非洲,若有行文不全或疏漏錯誤之處鸭限,懇請各位讀者批評指正,一路有你怪蔑,不勝感激里覆!

作者:小白師兄
鏈接:https://www.imooc.com/article/45936
來源:慕課網(wǎng)
本文原創(chuàng)發(fā)布于慕課網(wǎng) 丧荐,轉(zhuǎn)載請注明出處缆瓣,謝謝合作

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市虹统,隨后出現(xiàn)的幾起案子弓坞,更是在濱河造成了極大的恐慌,老刑警劉巖车荔,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渡冻,死亡現(xiàn)場離奇詭異,居然都是意外死亡忧便,警方通過查閱死者的電腦和手機族吻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來珠增,“玉大人超歌,你說我怎么就攤上這事〉俳蹋” “怎么了巍举?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凝垛。 經(jīng)常有香客問我懊悯,道長蜓谋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任炭分,我火速辦了婚禮桃焕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捧毛。我一直安慰自己覆旭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布岖妄。 她就那樣靜靜地躺著型将,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荐虐。 梳的紋絲不亂的頭發(fā)上七兜,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音福扬,去河邊找鬼腕铸。 笑死,一個胖子當(dāng)著我的面吹牛铛碑,可吹牛的內(nèi)容都是我干的狠裹。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼汽烦,長吁一口氣:“原來是場噩夢啊……” “哼涛菠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撇吞,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤俗冻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牍颈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迄薄,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年煮岁,在試婚紗的時候發(fā)現(xiàn)自己被綠了讥蔽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡画机,死狀恐怖冶伞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情色罚,我是刑警寧澤碰缔,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站戳护,受9級特大地震影響金抡,放射性物質(zhì)發(fā)生泄漏瀑焦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一梗肝、第九天 我趴在偏房一處隱蔽的房頂上張望榛瓮。 院中可真熱鬧,春花似錦巫击、人聲如沸禀晓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽粹懒。三九已至,卻和暖如春顷级,著一層夾襖步出監(jiān)牢的瞬間凫乖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工弓颈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帽芽,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓翔冀,卻偏偏與公主長得像导街,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纤子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351