【性能優化】瀏覽器加載,解析,渲染過程(在不考慮http協議、緩存、網絡等情況下)

前言:要優化瀏覽器性能就要先去了解瀏覽器加載解析頁面的過程。(這裏並沒有去考慮http協議,緩存,網絡等相關因素,這裏就只單純考慮html,css,js,圖片加載解析過程)。

 

一、瀏覽器加載,解析,渲染過程。

先看一個例子

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>瀏覽器加載、解析、渲染過程</title>
<script src="js1.js"></script>
<link href="css.css" rel="stylesheet"/>
<script>
	console.log('這是在hede中的js腳本');
	console.log(document.body + ' --獲取不到body,因爲下面的body元素還沒加載出來,腳本就已經執行了');   
	console.log('--------分割線--------');
	
	var oImg = new Image();
	oImg.src = "img.jpg";		//雖然在這裏就添加了圖片鏈接,但是瀏覽器會等html文檔中核心文件加載完纔開始加載圖片
	oImg.onload = function(){
		console.log('圖片加載完畢後執行');
	}
	
	window.addEventListener("load", function() {
		console.log('頁面加載完畢後執行該代碼');
	}, false);
	
	document.addEventListener("DOMContentLoaded", function() {
		console.log('當初始的HTML文檔被完全加載和解析完成之後後執行該代碼,不考慮樣式表,圖像,子框架是否加載完成');
		console.log('--------分割線--------');
	}, false);
	
</script>
<script src="js2.js"></script>
</head>

<body>
<div>
	<p>Hello world</p>
</div>
<script>
	console.log('這是在body中的js腳本');
	console.log(document.body + ' --這時候body元素已經加載出來了'); 
	console.log('--------分割線--------');
</script>
</body>
</html>

 

// js1文件內容
console.log('這是外部引用的JavaScript腳本js1');
console.log('--------分割線--------');
// js2文件內容
console.log('這是外部引用的JavaScript腳本js2');
console.log('--------分割線--------');

執行結果:(建議把代碼複製到編輯器上自己也執行一次,外部文件自己添加)

Network:文件加載情況

現在來分析下頁面加載,解析,渲染過程

①加載html文檔內容,加載完成後上往下進行解析。

②如果是遇到js外部鏈接,會馬上進行加載並解析,解析完馬上執行。如果遇到的是js腳本,也是解析完就馬上執行。(默認情況下,瀏覽器是同步加載 js 腳本,即渲染引擎遇到<script>標籤就會停下來,等到執行完腳本,再繼續向下渲染。這一點很重要,如果是在非本地情況下,js腳本加載需要時間,如果js文件過大,加載和執行時間過長,會堵塞瀏覽器向下渲染)

③如果是遇到css外部鏈接,會馬上進行請求加載並解析。如果遇到是css腳本,也是馬上解析。但是css解析完並非就馬上進行DOM元素的渲染,而是會轉化成cssom(css對象模型)的樹形結構,等待DOM節點樹的繪製完成。

等html文檔被完全加載和解析完成時,html代碼會轉化成DOM(文檔對象模型),同時也會繪製DOM節點樹。(等DOM節點樹繪製完成,會跟CSSOM一起,生成佈局(flow),並繪製(paint)

⑤最後就將繪製好的佈局渲染到屏幕上了,頁面也就展示在我們眼前了。

 

對上面例子的補充:

 

①、html文檔解析是從上往下解析的,js腳本是解析到哪就執行到哪,這也就是爲什麼在head中運行的腳本無法獲取到body,因爲body標籤還沒解析出來。

var oImg = new Image();
	oImg.src = "img.jpg";		//雖然在這裏就添加了圖片鏈接,但是瀏覽器會等html文檔中核心文件加載完纔開始加載圖片
	oImg.onload = function(){
		console.log('圖片加載完畢後執行');
	}

②、也正是因爲html文檔解析是從上往下解析,加載css樣式表最好寫在加載js文件前面,讓css先去加載,加快頁面的渲染。

③、圖片的加載是在js,css等核心文件加載完成之後纔會進行加載(這也就是爲什麼在圖片加載代碼後面的js2文件會比圖片先加載)。等圖片加載完成,因爲圖片有寬度高度什麼的,會改變頁面的佈局,這會導致頁面重新佈局(reflow),並重新繪製(repaint),並重新渲染。

④、如果後續的js文件中存在改變DOM節點樣式(如顏色)的代碼,會導致頁面會進行重新繪製(repaint)->重新渲染,但是不會導致重新佈局(reflow)。如果改變了DOM節點的大小或者改變DOM節點位置的話,將導致整個頁面重新佈局(reflow)->重新繪製(repaint)->重新渲染。

window.addEventListener("load", function() {
		console.log('頁面加載完畢後執行該代碼');
	}, false);
	
	document.addEventListener("DOMContentLoaded", function() {
		console.log('當初始的HTML文檔被完全加載和解析完成之後執行該代碼,不考慮樣式表,圖片,子框架是否加載完成');
		console.log('--------分割線--------');
	}, false);

⑤、window.onload相信大家見到過很多了,他是等頁面中所有文件(包括css,圖片等文件)加載完畢之後才執行裏面的代碼。

⑥、DOMContentLoad事件是當初始的HTML文檔被完全加載和解析完之後就會進行執行,他不考慮(css樣式表,或者圖片)是否加載完成。也就是jquery中的$(document).ready()。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章