国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

JavaScript無阻塞加載和defer、async詳解

2019-11-19 17:25:03
字體:
來源:轉載
供稿:網友

無阻塞加載

把js放在head里,瀏覽器是怎么去執(zhí)行它的呢,是按順序加載還是并行加載呢?在舊的瀏覽器下,都是按照先后順序來加載的,這就保證了加載的js依賴不會發(fā)生問題。但是少部分新的瀏覽器已經開始允許并行加載js了,也就是說可以同時下載js文件,但是還是按先后順序執(zhí)行文件的。

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

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

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

圖示動態(tài)腳本的下載

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

瀏覽器為了提升用戶體驗,加快UI線程的執(zhí)行是一個無法回避的問題,但是拆分js的下載和執(zhí)行是不可行的,如是乎瀏覽器換了種方式,這個方式也就是在同一個時間能下載多個資源。

將常用的,穩(wěn)定的靜態(tài)資源統(tǒng)一放在一個靜態(tài)資源服務器上,由統(tǒng)一的域名對外提供,這個域名要和主體請求的域名不一樣,原理是因為瀏覽器只通過域名來限制連接的個數,如果一個頁面里有兩個不同的域的,那么并行的http請求個數也會變成兩倍。有度,對DNS解析要開銷,所以2個最佳。

將所有外部js代碼分為UI初始化代碼和其他代碼,UI初始化代碼是在頁面加載時候執(zhí)行的代碼。讓那些不會用于頁面初始化展示的js代碼的加載和執(zhí)行操作通過onload事件在瀏覽器忙指示結束后觸發(fā),即讓那些和頁面加載無關的js腳本在onload方法里執(zhí)行

無阻塞加載腳本的核心技術就是動態(tài)的創(chuàng)建script的dom節(jié)點,而且可以跨域訪問。

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

動態(tài)腳本元素,就是說 <script> 標簽不是寫死在HTML中的,而是由現有的腳本生成的,因為 <script> 標簽也是DOM元素的一種,而JavaScript是可以通過DOM API操作DOM的。動態(tài)腳本只有在新建的script元素被添加到html文檔時開始下載,下載完立即執(zhí)行。

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

使用無阻塞腳本了,代碼置于head標簽還是html文檔底部也就無關緊要了。

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

腳本的異步執(zhí)行,會產生前后依賴的問題。在腳本加載執(zhí)行完畢后,非ie瀏覽器會觸發(fā)該 <script> 元素的 onload 事件,ie瀏覽器下有onreadystatechange事件,我們可以將回調放到這個事件中處理。

每當瀏覽器解析到<script>標簽(無論內嵌還是外鏈)時,瀏覽器會優(yōu)先下載、解析并執(zhí)行該標簽中的javaScript代碼,而阻塞其后所有頁面內容的下載和渲染。(也就是說外部js的下載也會阻塞別的線程,目前有少部分瀏覽器支持并行下載js)

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

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

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

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

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

async(異步)是HTML5新增的屬性,該屬性的作用是讓瀏覽器能并行下載腳本且不阻塞瀏覽器的文檔解析和渲染,下載完成后腳本立即執(zhí)行,可能無序執(zhí)行,取決于下載完成的時間)

若瀏覽器同時支持上述兩種屬性且script標簽同時具有這兩種屬性,則async屬性會優(yōu)于defer生效。

在不支持async屬性的瀏覽器里,可以通過動態(tài)創(chuàng)建script元素并插入文檔中,實現腳本的異步載入和執(zhí)行:

requirejs就是使用這個方法實現的。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 金沙县| 阳春市| 稻城县| 泰来县| 吴旗县| 云和县| 黑龙江省| 湖北省| 湖南省| 富顺县| 大方县| 奉化市| 台江县| 织金县| 龙江县| 炉霍县| 临桂县| 昌乐县| 乌什县| 祁东县| 天镇县| 蕉岭县| 栖霞市| 民县| 白河县| 巴里| 天峨县| 新安县| 南川市| 轮台县| 左贡县| 屏边| 水富县| 化州市| 泗洪县| 塔城市| 临泉县| 全南县| 清丰县| 镇雄县| 青州市|