高性能 javascript 之無阻塞加載 script

執行javascript的代碼會阻塞其他文件的下載

<script>標籤每次出現都會霸道地讓頁面等待腳本的解析和執行,無論當前的javascript代碼是內嵌還是包含在外鏈文件中,頁面的下載和渲染都會停下來等待腳本執行完成。

例如:

<html>
	<head>
		<title>Script Example</title>
		<script type="text/javascript" src="file1.js"></script>
		<script type="text/javascript" src="file2.js"></script>
		<script type="text/javascript" src="file3.js"></script>
		<link rel="stylesheet" type="text/css" href="styles.css">
	</head>
	<body>
		<p>Hello world!</p>
	</body>
</html>

這些看似正常的代碼實際上有十分嚴重的性能問題:在<head>中加載三個javascript文件。由於腳本會阻塞頁面渲染,直到它們全部下載並執行完成後,頁面的渲染纔會繼續。可以看下執行過程中的瀑布圖:
在這裏插入圖片描述
由於腳本會阻塞頁面其他資源的下載,因此推薦將所有的<script>標籤儘可能放到body標籤底部,即</body>上面。

動態腳本元素

用標準的DOM方法可以很容易的創建一個新的script元素:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "file1.js";
document.getElementByTagName("head")[0].appendChild("script");

這個新創建的script元素加載了file1.js文件。文件在該元素被添加到頁面時開始下載。這種技術的重點在於:無論在何時啓動,文件的下載和執行過程都不會阻塞頁面其他進程。甚至可以將代碼放到<head>區域不會影響頁面其他部分。

推薦的無阻塞模式:

<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
	loadScript("the-rest.js",function() {
		Application.init();
	});
</script>

把這段代碼放到</body>閉合標籤之前。另一種方法是將loadScript()函數直接嵌入頁面,從而避免多產生一次HTTP請求。例如:

<script type="text/javascript">
	function loadScript(url,callback) {
		var script = document.createElement("script");
		script.type = "text/javascript";

		if(script.readyState) { // IE 這種基本不需要考慮了,ie 的份額很低,基本淘汰了
			script.onreadystatechange = function() {
				if (script.readyState == "loaded" || cript.readyState == "complete") {
					script.onreadystatechange = null;
					callback();
				}
			}
		}else { // 其他瀏覽器
			script.onload = function() {
				callback();
			}
		}
		script.src = url;
		document.getElementByTagName("head")[0].appendChild("script");
	}
	
	loadScript("the-rest.js",function(){
		Application.init();
	})
</script>

優化建議

  • </body>閉合標籤前,將所有的<script>標籤放到頁面底部。這能確保在腳本執行前頁面已經完成了渲染。

  • 合併腳本。頁面中的<script>標籤越少,加載也就越快,響應也更迅速。無論外鏈文件還是內嵌腳本都是如此。

  • 有多種無阻塞下載JavaScript的方法:

    1、使用script標籤的deferasync屬性,這兩者的相同點是採用並行下載,在下載的過程中不會產生阻塞。區別在於執行時機,async是加載完後自動執行,而defer需要等待頁面完成後執行。
    2、使用動態創建的<script>元素來下載並執行代碼。
    3、使用XHR對象下載javascript代碼並注入頁面中。

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