首頁  >  文章  >  web前端  >  JavaScript無阻塞載入和defer、async

JavaScript無阻塞載入和defer、async

高洛峰
高洛峰原創
2017-02-28 14:38:551166瀏覽

無阻塞載入

把js放在head裡,瀏覽器是怎麼去執行它的呢,是依序載入還是並行載入呢?在舊的瀏覽器下,都是按照先後順序來載入的,這就保證了載入的js依賴不會發生問題。但是少部分新的瀏覽器已經開始允許並行載入js了,也就是說可以同時下載js文件,但還是按先後順序執行文件的。

下載是異步的沒問題,但是每個javascript執行的時候還是同步的,就是先出現的script標籤一定是先執行,即使是並行下載它是最後一個下載完成的,除非標有defer的script標籤。任何javascript在執行的時候都會中斷目前html文檔解析,自然會阻止頁面渲染。

javascript載入是不會影響已經渲染的頁面,但是會中斷html文檔解析,瀏覽器會在javascript執行以後決定當前文檔是否需要重新渲染或文檔重排。所以即使javascript放到最後也會讓瀏覽器暫停,但不影響先前已經解析出來的dom文檔,此時對使用者來說是可操作的。

javascript下載完畢之後會立即執行,所有的javascript執行都會阻塞瀏覽器的其他行為,例如阻塞其他javascript的執行、其他的http請求的執行以及頁面的解析和渲染。 (html文件中外部js的下載也會阻塞瀏覽器的行為,但透過建立script元素動態js的下載不會,可能是認為動態的js不會改變頁面效果,所以允許資源並行下載。)

JavaScript無阻塞載入和defer、async

圖示動態腳本的下載

UI執行緒會根據頁面裡資源(資源是指css文件,圖片等等)書寫的先後順序來載入資源,加載資源也就是使用http請求獲取資源,像css外部文件,html文件以及圖片等資源http請求處理完畢也就意味著資源加載結束,但是像外部的javascript文件的加載則不同,它的加載過程被分為兩步,第一步和載入css文件和圖片一樣,就是執行一個http請求下載外部的js文件,但是javascript完成http操作後並不意味著操作完畢,UI線程接著會執行它。 js腳本的下載和執行必須是一個完整的操作,是不能被割裂的。動態js的下載不會阻塞,但執行一定會。

瀏覽器為了提升使用者體驗,加快UI執行緒的執行是一個無法迴避的問題,但是分割js的下載和執行是不可行的,如是乎瀏覽器換了種方式,這個方式也就是在同一個時間能下載多個資源。

將常用的,穩定的靜態資源統一放在一個靜態資源伺服器上,由統一的網域對外提供,這個網域要和主體請求的網域不一樣,原理是因為瀏覽器只透過網域來限制連線的個數,如果一個頁面裡有兩個不同的網域的,那麼並行的http請求個數也會變成兩倍。有度,對DNS解析要開銷,所以2個最佳。

將所有外部js程式碼分為UI初始化程式碼和其他程式碼,UI初始化程式碼是在頁面載入時候執行的程式碼。讓那些不會用於頁面初始化展示的js程式碼的載入和執行操作透過onload事件在瀏覽器忙碌指示結束後觸發,也就是讓那些和頁面載入無關的js腳本在onload方法裡執行

無阻塞載入腳本的核心技術就是動態的創建script的dom節點,而且可以跨網域存取。

var script=document.createElement("script");

script.type="text/javascript";

script.src="file.js";

document.getElementsByTagName("head")[0].appendChild(script);

動態腳本元素,就是說<script> 標籤不是寫死在HTML中的,而是由現有的腳本產生的,因為&lt ;script> 標籤也是DOM元素的一種,而JavaScript是可以透過DOM API操作DOM的。動態腳本只有在新建的script元素被加入到html文件時開始下載,下載完立即執行。 </script>

無阻塞腳本的好處就是不會阻塞UI的執行,也不會影響其他同步js程式碼的執行,不無阻塞腳本改變了腳本的載入順序,所以在使用無阻塞腳本時候一定要更注意腳本之間的依賴關係,確保整個頁面的腳本都能正常執行。

使用無阻塞腳本了,程式碼置於head標籤還是html文檔底部也就無關緊要了。

頁面載入的總時間不是衡量頁面載入快速的標準,頁面同步阻塞載入的時間才是衡量頁面載入效率的準確標準,非阻塞腳本載入可能會增加整個頁面載入的時間,但是它可以減少頁面阻塞載入的時間。

腳本的非同步執行,會產生前後依賴的問題。在腳本載入執行完畢後,非ie瀏覽器會觸發該 <script> 元素的 onload 事件,ie瀏覽器下方有onreadystatechange事件,我們可以將回調放到這個事件中處理。 </script>

每當瀏覽器解析到<script>標籤(無論內嵌或外鏈)時,瀏覽器會優先下載、解析並執行該標籤中的javaScript程式碼,而阻塞其後所有頁面內容的下載和渲染。 (也就是說外部js的下載也會阻塞別的線程,目前有少部分瀏覽器支援並行下載js)</script>

無阻塞載入腳本技術的核心就是:動態下載js腳本的時候,不會阻塞UI線程的執行。動態腳本為什麼不阻塞ui執行緒?可能是因為瀏覽器認為動態資源不會影響頁面渲染。

讓script延遲和非同步的兩個屬性:defer和async

js腳本會改變文件輸入流的內容,所以執行js時會暫停頁面的渲染。對於內聯腳本沒什麼問題,因為腳本和html文檔同時載入了。但對於外部引入的腳本,腳本的下載(取決於網速)也會阻塞瀏覽器文件的解析和渲染,甚至會阻塞有些瀏覽器下載別的資源(目前有些瀏覽器已經實現並行下載)。所以出現defer和async屬性,優化頁面的顯示。

defer(延遲)是html4.0中定義的,該屬性使得瀏覽器能延遲腳本的下載,等document文檔載入和解析完成後,按照他們在文檔中出現順序再去下載解析。也就是說defer屬性的<script>就類似將<script>放在body底部的效果,會在document的DOMContentLoaded事件之前執行。 </script>

將腳本放在body底部比為腳本增加defer屬性讓腳本延遲載入更好。

async(非同步)是HTML5新增的屬性,此屬性的作用是讓瀏覽器能並行下載腳本且不阻塞瀏覽器的文件解析與渲染,下載完成後腳本立即執行,可能無序執行,取決於下載完成的時間)

若瀏覽器同時支援上述兩種屬性且script標籤同時具有這兩種屬性,則async屬性會優於defer生效。

在不支援async屬性的瀏覽器裡,可以透過動態建立script元素並插入文件中,實現腳本的非同步載入和執行:

JavaScript無阻塞載入和defer、async

# #requirejs就是用這個方法實作的。

更多JavaScript無阻塞載入和defer、async相關文章請關注PHP中文網!



#

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn