1. 程式人生 > >瀏覽器渲染一個頁面都幹了哪些事

瀏覽器渲染一個頁面都幹了哪些事

【編者按】其實,有關網頁渲染的文章很多,但是相關資訊比較分散,且論述並不是很完整。如果要想對這個主題有個大致的瞭解,我們還得學習很多知識。因此,Web開發者Alexander Skutin 決定寫一篇文章。他相信,這篇文章不僅能幫助初學者,也能對那些想要重新整理知識結構的高階前端開發者有所裨益。原文地址

譯文如下:

網頁渲染必須在很早的階段進行,可以早到頁面佈局剛剛定型。因為樣式和指令碼都會對網頁渲染產生關鍵性的影響。所以專業開發者必須瞭解一些技巧,從而避免在實踐的過程中遇到效能問題。

這篇文章不會研究瀏覽器內部的詳細機制,而是提出一些通用的規則。畢竟,不同瀏覽器引擎的工作機制各不相同,這無疑會讓開發者對瀏覽器特性的研究變得更加複雜。

瀏覽器是如何完成網頁渲染?

首先,我們回顧一下網頁渲染時,瀏覽器的動作:

  1. 根據來自伺服器端的HTML程式碼形成文件物件模型(DOM)
  2. 載入並解析樣式,形成CSS物件模型。
  3. 在文件物件模型和CSS物件模型之上,建立一棵由一組待生成渲染的物件組成的渲染樹(在Webkit中這些物件被稱為渲染器或渲染物件,而在Gecko中稱之為“frame”。)渲染樹反映了文件物件模型的結構,但是不包含諸如標籤或含有display:none屬性的不可見元素。在渲染樹中,每一段文字字串都表現為獨立的渲染器。每一個渲染物件都包含與之對應的DOM物件,或者文字塊,還加上計算過的樣式。換言之,渲染樹是一個文件物件模型的直觀展示。
  4. 對渲染樹上的每個元素,計算它的座標,稱之為佈局。瀏覽器採用一種流方法,佈局一個元素只需通過一次,但是表格元素需要通過多次。

  5. 最後,渲染樹上的元素最終展示在瀏覽器裡,這一過程稱為“painting”。

當用戶與網頁互動,或者指令碼程式改動修改網頁時,前文提到的一些操作將會重複執行,因為網頁的內在結構已經發生了改變。

重繪

當改變那些不會影響元素在網頁中的位置的元素樣式時,譬如background-color(背景色), border-color(邊框色), visibility(可見性),瀏覽器只會用新的樣式將元素重繪一次(這就是重繪,或者說重新構造樣式)。

重排

當改變影響到文字內容或結構,或者元素位置時,重排或者說重新佈局就會發生。這些改變通常由以下事件觸發:

  • DOM操作(元素新增,刪除,修改,或者元素順序的改變);
  • 內容變化,包括表單域內的文字改變;
  • CSS屬性的計算或改變;
  • 新增或刪除樣式表;
  • 更改“類”的屬性;
  • 瀏覽器視窗的操作(縮放,滾動);
  • 偽類啟用(:懸停)。

瀏覽器如何優化渲染?

瀏覽器儘可能將重繪/重構 限制在被改變元素的區域內。比如,對於位置固定或絕對的元素,其大小改變隻影響元素本身及其子元素,然而,靜態定位元素的大小改變會觸發後續所有元素的重流。

另一種優化技巧是,在執行幾段JavaScript程式碼時,瀏覽器會快取這些改變,在程式碼執行完畢後再將這些改變經一次通過加以應用。舉個例子,下面這段程式碼只會觸發一個重構和重繪:

  1. var $body = $('body');
  2. $body.css('padding','1px');// reflow, repaint
  3. $body.css('color','red');// repaint
  4. $body.css('margin','2px');// reflow, repaint
  5. // only 1 reflow and repaint will actually happen

然而,如前所述,改變元素的屬性會觸發強制性的重排。如果我們在上面的程式碼塊中加入一行程式碼,用來訪問元素的屬性,就會發生這種現象。

  1. var $body = $('body');
  2. $body.css('padding','1px');
  3. $body.css('padding');// reading a property, a forced reflow
  4. $body.css('color','red');
  5. $body.css('margin','2px');

其結果就是,重排發生了兩次。因此,你應該把訪問元素屬性的操作都組織在一起,從而優化網頁效能。(你可以在JSBin查到更為詳細的例子

有時,你必須觸發一個強制性重排。比如,我們必須將同樣的屬性(比如左邊距)兩次賦值給同一個元素。起初,它應該設定為100px,且不帶動效。接著,它必須通過過渡(transition)動效改變為50px。你現在可以在JSbin上學習這個例子,不過我會在這兒更詳細地介紹它。

首先,我們建立一個帶過渡效果的CSS類:

  1. .has-transition {
  2. -webkit-transition: margin-left 1s ease-out;
  3. -moz-transition: margin-left 1s ease-out;
  4. -o-transition: margin-left 1s ease-out;
  5. transition: margin-left 1s ease-out;
  6. }

然後繼續執行:

  1. // our element that has a "has-transition" class by default
  2. var $targetElem = $('#targetElemId');
  3. // remove the transition class
  4. $targetElem.removeClass('has-transition');
  5. // change the property expecting the transition to be off, as the class is not there
  6. // anymore
  7. $targetElem.css('margin-left',100);
  8. // put the transition class back
  9. $targetElem.addClass('has-transition');
  10. // change the property
  11. $targetElem.css('margin-left',50);

然而,這個執行無法奏效。所有改變都被快取,只在程式碼塊末尾加以執行。我們需要的是強制性的重排,我們可以通過以下更改加以實現:

  1. // remove the transition class
  2. $(this).removeClass('has-transition');
  3. // change the property
  4. $(this).css('margin-left',100);
  5. // trigger a forced reflow, so that changes in a class/property get applied immediately
  6. $(this)[0].offsetHeight;// an example, other properties would work, too
  7. // put the transition class back
  8. $(this).addClass('has-transition');
  9. // change the property
  10. $(this).css('margin-left',50);

現在程式碼如預期那樣執行了。

有關效能優化的實際建議

總結現有的資料,我提出以下建議:

  • 建立有效的HTML和CSS檔案,不要忘記指明文件的編碼方式。樣式應該包含在標籤內,指令碼程式碼則應該加在標籤末端。
  • 儘量簡化和優化CSS選擇器(這種優化方式幾乎被使用CSS前處理器的開發者統一忽視了)將巢狀程度保持在最低水平。以下是CSS選擇器的效能排名(從最快者開始)

    1. 識別器:#id
    2. 類:.class
    3. 標籤:div
    4. 相鄰兄弟選擇器:a + i
    5. 父類選擇器:ul> li
    6. 通用選擇器:*
    7. 屬性選擇:input[type="text"]
    8. 偽類和偽元素:a:hover

你應該記住,瀏覽器在處理選擇器時依照從右到左的原則,因此最右端的選擇器應該是最快的:#id或則.class:

  1. div *{...}// bad
  2. .list li {...}// bad
  3. .list-item {...}// good
  4. #list .list-item {...} // good
  • 1.在你的指令碼程式碼中,儘可能減少DOM操作。快取所有東西,包括元素屬性以及物件(如果它們被重用的話)。當進行復雜的操作時,使用“孤立”元素會更好,之後可以將其加到DOM中(所謂“孤立”元素是與DOM脫離,僅儲存在記憶體中的元素)。

  • 2.如果你使用jQuery來選擇元素,請遵從jQuery選擇器最佳實踐方案。

  • 3.為了改變元素的樣式,修改“類”的屬性是奏效的方法之一。執行這一改變時,處在DOM渲染樹的位置越深越好(這還有助於將邏輯與表象脫離)。

  • 4.儘量只給位置絕對或者固定的元素新增動畫效果。

  • 5.在使用滾動時禁用複雜的懸停動效(比如,在中新增一個額外的不懸停類)。讀者可以閱讀關於這個問題的一篇文章

想了解更多的細節問題,大家也可以看看這兩篇文章:

相關推薦

瀏覽器渲染一個頁面哪些

【編者按】其實,有關網頁渲染的文章很多,但是相關資訊比較分散,且論述並不是很完整。如果要想對這個主題有個大致的瞭解,我們還得學習很多知識。因此,Web開發者Alexander Skutin 決定寫一篇文章。他相信,這篇文章不僅能幫助初學者,也能對那些想要重新整理知識結構的

瀏覽器輸入url後些什麼?

我們在瀏覽器中輸入網址。 瀏覽器查詢域名對應的IP地址 -DNS查詢過程為: -瀏覽器快取->系統快取->路由器快取->ISP DNS快取->遞迴搜尋 -遞迴搜尋過程

輸入一個url到瀏覽器頁面展示經歷哪些過程

在日常的瀏覽器訪問過程中,我們肯定會訪問n多頁面,但是我們輸入一個網址後是如何變成一個頁面展示在我們面前,從一個url到頁面的展示這個過程中,我們的瀏覽器都經歷了一些什麼? 步驟 → 1- 輸入網址 → 2- 快取解析 →

從輸入一個url到瀏覽器頁面展示經歷哪些過程

面試的時候有些面試官會問這個問題,可按如下流程作答: 1、首先,在瀏覽器位址列中輸入url 2、瀏覽器先檢視瀏覽器快取-系統快取-路由器快取,如果快取中有,會直接在螢幕中顯示頁面內容。若沒有,則跳到第三步操作。 3、在傳送http請求前,需要域名解析(DNS解析),解析

瀏覽器位址列裡輸入一個URL開始,到出現整個頁面,網路上發生什麼

最近談到這個問題,覺得自己不能夠清楚的講明白這個過程的一些細節,所以差了些資料,覺得如下的解答還是比較詳細的,後期還會慢慢完善這個過程中不足的地方。回車前: 1. 如果用某些輸循入法輸入, 它會按標準結果、快取匹配、傳送到去端匹配, 給你幾個聯想結果。  你對結果的修改會反

瀏覽器輸入域名到展示頁面發生什麽

blog 展示 完成 結果 pos 組成 大致 域名解析 服務 DNS域名解析先找本地hosts文件,檢查對應域名ip的關系,有則想ip地址發送請求,沒有再去找DNS服務器 建立TCP連接拿到服務器IP後,向服務器發送求求,三次握手,建立TCP連接簡單理解三次握手:客戶

關於類、方法、對象(實例):通過一個例子看一下self哪些事情

就會 就是 style 寫代碼 obj 這一 charm self 將不 我們在定義一個類時,經常會在類的各個方法中看到self,那麽在程序執行時self到底起了什麽作用,什麽時候要加self,這一點需要我們思考並好好理解。之前在學習時沒有想這麽多,加之用p

一個程式在執行main函式之前些什麼?

《一 》怎麼執行程式(如何把程式載入到記憶體上 首先記憶體需要的是資料和指令(機器語言)但是程式是高階語言, 1:先通過編譯連結生成.exe檔案(.exe檔案在磁碟中儲存,且.exe檔案中是機器語言) 2:.exe檔案通過mmap函式對映到虛擬記憶體上 3:再通過分段

月薪3萬的程序員避開哪些坑?

女人 沒有 是什麽 導致 即使 -1 不知道 準備 很快 程序員薪水有高有低,有的人一個月可能拿30K、50K,有的人可能只有2K、3K。同樣有五年工作經驗的程序員,可能一個人每月拿20K,一個拿5K。是什麽因素導致了這種差異?我特意總結了容易導致薪水低的九大行為

付出哪些努力

經理 逆向分析 有客 過程 思考 可能 日程 print 機會 我們常常會在一件事情的結果不如人意時感到委屈和憤懣(尤其是被別人指摘時):我已經非常努力了啊,為什麽會這樣! 但是,你有客觀地思考過這幾個問題嗎: 你究竟付出了哪些努力呢? 你是不是在

點擊頁面的按鈕,使之打開一個新窗口,加載一個頁面的方法有哪些呢?

body del .html blank oca pos type target put 1.<base target="_blank" /> 頁面只要有a標簽,都會打開一個新的頁面; 2.<input type=‘button‘ value=‘new‘

9大Python最常用的數據分析庫,在2018哪些更新?

包括 有用 樣式 代數 scrip 小部件 很快 scipy 圖庫 1. NumPy 一般我們會將科學領域的庫作為清單打頭,NumPy是該領域的主要軟件庫之一。它旨在處理大型的多維數組和矩陣,並提供了很多高級的數學函數和方法,因此可以用它來執行各種操作。 在

記錄一下從9.25-10.19出發去沈陽區域賽前俺些啥

多校 博客 區域 區域賽 實驗 女生 打了 bsp 一點 9.25: 前幾天打了2017年西安,南寧兩場區域賽,被虐的說不出話來,覺得自己啥也不會,特別西安線段樹專場,覺得線段樹應該惡補一下,南寧場覺得也不是那麽簡單,可也要快速出四題才能拿銅,這意味著我要麽得寫出pell方

為了完畢月入三萬的目標,我哪些準備?

1 我覺得像我這般年紀的(29歲)。有相對紮實技術功底的(就不自謙了)。對賺錢有著強烈慾望的程式猿,應該定一個切實的小目標——五年內月入三萬! 之所以要定這個目標,最基本的原因是老婆的批評刺痛了我——一個身強力壯的年輕男子(腦子也還好使),不想方設法的多掙點錢,

周志華等提出RNN可解釋性方法,看看RNN內部些什麼

選自 ArXiv,作者:Bo-Jian Hou, Zhi-Hua Zhou,機器之心編譯,參與:思源、曉坤。 除了數值計算,你真的知道神經網路內部在做什麼嗎?我們一直理解深度模型都靠裡面的運算流,但對於是不是具有物理意義、語義意義都還是懵懵懂懂。尤其是在迴圈神經網路中,我們只知道每一個時間步它都在利

我學Python哪些

前言        2017年11月29日,自己曾在公眾號內寫過一篇《聊聊我的R語言學習路徑和感受》的文章,受到了很多朋友的關注和讚揚,同時,也有其他公眾號在幫忙轉載。當然,也有很多朋友也給我留言,能不能聊聊關於Pyt

http請求過程(訪問一個頁面,發生怎樣的網路請求?)

域名解析->域名 ->快取->根域dns->頂級域dns->本域dns->伺服器IP 1.搜尋瀏覽器自身DNS快取,如果不存在或者過期(>60s)放棄 2.搜尋作業系統自身的dns快取 3.讀取本地的HOST檔案 4.瀏覽器發起一個DNS的

雲吶IT互動服務檯V3.5.0版本更新哪些功能

雲吶it互動服務檯具體功能更新內容如下: 【Web端版本更新內容】 1、新增網頁組建、微信接入、app-SDK、小程式四種渠道進行快速報障 2、新增在專案中生成對應的服務報表功能; 3、新增資產可分類設定自定義欄位功能; 4、當員工不在職時,可將其待辦的工作批量轉交給他人;

swoft| 原始碼解讀系列二: 啟動階段, swoft 些啥?

date: 2018-8-01 14:22:17title: swoft| 原始碼解讀系列二: 啟動階段, swoft 都幹了些啥?description: 閱讀 sowft 框架原始碼, 瞭解 sowft 啟動階段的那些事兒 小夥伴剛接觸 swoft 的時候會感覺 壓力有點大, 更直觀的說法是 難. 開發

maven打war包的過程中,哪些外掛呢?

一、maven生命週期 http://ifeve.com/introduction-to-the-lifecycle/   https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html &nbs