遊覽器中javascript的執行過程(圖文)

來源:互聯網
上載者:User

1. 大多數遊覽器的組件構成

在最底層的三個組件分別是網路,UI後端和js解譯器。作用如下:
(1)網路- 用來完成網路調用,例如http請求,它具有平台無關的介面,可以在不同平台上工作
(2)UI 後端- 用來繪製類似組合選擇框及對話方塊等基本組件,具有不特定於某個平台的通用介面,底層使用作業系統的使用者介面
(3)JS解譯器- 用來解釋執行JS代碼

ps:和知識點主要來自《HOW BROWSERS WORK: BEHIND THE SCENES OF MODERN WEB BROWSERS》 想深入瞭解的同學可以重點看下。
2. 大多數遊覽器(比如chrome)讓一個單線程共用於執行javascrip和更新使用者介面。這個線程通常被稱為“遊覽器UI線程”, 每個時刻只能執行其中一種操作,這意味著當Javascript代碼正在執行時使用者介面無法響應輸入,反之亦然。這樣做是因為javascript代碼的作用就是操作DOM更新使用者介面,用同一個線程來做負責這兩件事情可以更高效
3. 遊覽器UI線程的工作基於一個簡單的隊列系統,任務會被儲存到隊列中直到進程空閑。一旦空閑,隊列中的下一個任務就被重新提取出來並運行。這些任務要麼是運行javascript代碼,要麼執行UI更新,包括重繪和重排。
4. 重點再強調下,javascript是單線程運行,千萬別被setTimeout()和setInterVal()這種函數迷惑而誤以為它是多線程。
ok,基礎點講解完畢,讓我們進入正題,來講解在遊覽器中javascript的執行過程。
一、原理
一般而言,<script>標籤每次出現都會霸道地讓頁面等待指令碼的解析和執行,無論當前的Javascript是內嵌的還是包含了外鏈檔案,頁面的下載和渲染都必須停下來等待指令碼執行完成。這在頁面的生存周期中是必要的,因為指令碼執行過程中可能修改頁面內容,一個典型的例子就是在頁面中使用document.write()。
當javascript代碼是內嵌在html裡面時,這點還是比較容易理解,但當javascript是外鏈檔案時稍微有點負載,因為存在一個載入過程,而且遊覽器載入好這個js檔案之後往往還對其緩衝。
首先,我們用以下這個例子來說明下緩衝問題 複製代碼 代碼如下:<html>
<head>
<script type='text/javascript' src='js/f2.js'></script>
</head>
<body>
</body>
</html>

第一次開啟頁面時:

第二次開啟頁面時:

從上例中可以明顯看出,像chrome之類的高版本遊覽器會對js檔案進行緩衝,作用是不言而喻,減少網路請求。

其次,第二個問題,當一個javascript檔案被載入時是否會阻塞其他javascript檔案或者其他檔案的載入。《高效能Javascript》一書中對這個問題做了較好的解答:各種遊覽器的低版本的處理是當一個javascript檔案在載入時,會同時阻塞頁面其他檔案的載入(包括其他javascript檔案),但IE8,Firfox3.5,Safari 4和Chrome 2都允許並行下載javascript檔案,但遺憾的是,javascript下載過程仍然會組舍其他資源的下載,比片。儘管javascript指令碼的下載過程不會相互影響,但頁面仍然必須等待所有的javascript代碼下載並執行完成才能繼續。

這裡說句題外話:遊覽器對同一網域名稱下的並發連結數也是有限制的,其他一些參數如下:

二、技巧
1. 指令碼位置
由於指令碼會阻塞頁面其他資源的下載,因此推薦將所有的<script>標籤放到<body>標籤的底部,已盡量減少對整個頁面下載的影響。
2. 將能合并的js檔案合并
3. 無阻塞指令碼
現在比較常用的方法就是動態載入執行指令碼。你的原理是通過DOM,你幾乎可以用Javascript動態建立HTML中的所有內容,其根本在於,<script>標籤與頁面中其他元素並無差異:都能通過DOM引用,都能在文檔中移動,刪除和建立。檔案在改該<script>元素被添加到頁面時開始現在,它不會阻止其他檔案下載,只在執行階段阻塞渲染。特彆強調:《高效能javascript》一文中說“這種技術的重點在於:無論何時啟動下載,檔案的下載和執行都不會阻塞頁面其他進程”,這並不是說它在執行不會阻塞其他javascript代碼,而是要強調不會阻塞其他資源的下載等其他任務。
具體的代碼如下:

複製代碼 代碼如下:function loadScript(url){
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = url;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
}

4. 神奇的setTimeout()
這裡我不過多的將setTimeout()的原理,有興趣的讀者可以具體去看《高效能javascript》的第六章。我重點強調下,setTimeout的第二個參數並不是一個精確的時間,二是必須在javascript線程空閑時才能運行。利用這個特性,如下代碼簡單可以實現等待其他js代碼執行完畢後再執行function裡面的代碼。 複製代碼 代碼如下:setTimeout(function(){
// do some before other javascripe codes had processed
}, 25)

但在function裡面不要使用document.write()方法,因為執行setTimeout裡面函數時往往已經到了頁面onload之後,此時再執行 document.write 將導致當前頁面的內容被清空,因為它會自動觸發 document.open 方法。
《高效能Javascript》
HOW BROWSERS WORK: BEHIND THE SCENES OF MODERN WEB BROWSERS
Google Chrome源碼剖析【一】:多執行緒模式
javascript非同步載入詳解

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.