1. 程式人生 > >js 非同步載入

js 非同步載入

一、為什麼要JS非同步載入?

因為同步載入存在問題!

JS在預設情況下是以同步模式(又稱阻塞模式)載入的,這裡“載入”的意思是“解釋、執行”。在最新版本的瀏覽器中,瀏覽器對於程式碼請求的資源都是瀑布式的載入,而不是阻塞式的,但是JS的執行總是阻塞的。這會引起什麼問題呢?如果在頁面中載入一些JS,但其中某個請求遲遲得不到響應,位於此JS後面的JS將無法執行,同時頁面渲染也不能繼續,使用者看到的就是白屏(此時JS在<head>標籤之後引入)

<head>
       <meta charset="UTF-8"> <title>test</title> <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> </head> <body> <p>我是小仙女</p> </body> 

這是一個簡單的html檔案,頁面的主體是簡單地文字段落,但是程式碼執行後遲遲都是空白。為什麼呢?因為第一個請求的JS遲遲無法載入,於是阻塞了後面程式碼的執行,頁面得不到渲染。
那該怎麼辦呢?你可能會想到一個方法,把JS程式碼放到</body>標籤之前!好主意!於是我們把JS放在HTML語句後面(這也是所提倡的頁面結構)。

<head>
    <meta charset="UTF-8"> <title>test</title> </head> <body> <p>我是小仙女</p> <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> </body> 

頁面瞬間被渲染,問題似乎解決了,可是...

<head>
    <meta charset="UTF-8"> <title>test</title> </head> <body> <p>我是小仙女</p> <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> alert("hello world"); </script> </body> 

我們在前面程式碼的基礎上簡單加了一段程式碼,但"hello world"遲遲無法被彈出,顯然是因為前面的JS請求阻塞了後面程式碼的載入。這時同步載入的問題依然存在:改變JS的載入位置只能改變頁面的渲染,JS還是會阻塞。

二、如何實現JS非同步載入?

非同步載入即非阻塞載入,瀏覽器在載入JS的同時,還會繼續進行後續頁面的處理。在本例中,我們想實現在請求第一段谷歌提供的JS的同時,下面的JS不受影響,繼續執行。
如何實現?現在提供常用的幾種方法:

1.動態生成<script>標籤
<head>
    <meta charset="UTF-8"> <title>test</title> </head> <body> <p>我是小仙女</p> <script type="text/javascript"> (function(){ var s=document.createElement("script"); s.type="text/javascript"; s.src="http://china-addthis.googlecode.com/svn/trunk/addthis.js"; document.body.appendChild(s); })(); </script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> alert("hello world"); </script> </body> 

但是上面的程式碼還有點問題,這種載入方式在載入執行完之前會阻止onload事件的觸發,而現在很多頁面的程式碼都在onload時執行額外的渲染工作等,所以還是會阻塞部分頁面的初始化處理。

<head>
    <meta charset="UTF-8"> <title>test</title> </head> <body> <p>我是小仙女</p> <script type="text/javascript"> (function(){ //function lazy(){ var s=document.createElement("script"); s.type="text/javascript"; s.src="http://china-addthis.googlecode.com/svn/trunk/addthis.js"; document.body.appendChild(s); // } // window.addEventListener("load",lazy,false); })(); window.onload=function(){ alert("hello world"); }; </script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> </body> 

上面帶註釋的程式碼不能很好的渲染"hello world",因為存在阻塞onload事件問題;可以把註釋去掉,讓谷歌提供的JS在onload時才開始非同步載入,這就解決了上述問題。

2.async屬性

async是HTML5的新屬性,該屬性規定一旦指令碼可用,則會非同步執行(一旦下載完畢就會立刻執行)。
需要注意的是:async屬性僅適用於外部指令碼(只有在使用src屬性時)。

<head>
    <meta charset="UTF-8"> <title>test</title> </head> <body> <p>我是小仙女</p> <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' async="async"></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> alert("hello world"); </script> </body> 
3.defer屬性

defer屬性規定是否對指令碼執行進行延遲,直到頁面載入為止。
之前只有IE的hack支援defer屬性,現在H5開始全面支援defer屬性。

<head>
    <meta charset="UTF-8"> <title>test</title> </head> <body> <p>我是小仙女</p> <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' defer="defer"></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> alert("hello world"); </script> </body> 

asyncdefer看起來差不多呀?而且經常一起出現!來辨析一下

a.如果沒有asyncdefer屬性,那麼瀏覽器會立即執行當前的JS指令碼,阻塞後面的指令碼;
b.如果有async屬性,載入和渲染後續文件的過程和當前JS的載入與執行並行進行(非同步),它是亂序執行的,不管你宣告的順序如何,只要它載入完了就會執行;
c.如果有defer屬性,載入後續文件元素的過程和JS的載入是並行進行(非同步)的,但是JS的執行在所有元素解析完成之後進行,而且它是按照載入順序執行指令碼的
4.其他方式

a.XHR注入(通過XMLHttpRequest物件來獲取JS,然後建立一個script元素插入到DOM結構中);
b.ajax eval(使用ajax得到指令碼內容,然後通過eval(xmlhttp.responseText)來執行指令碼);
c.iframe等



作者:尋找薛定諤的貓
連結:https://www.jianshu.com/p/3aa3a3e27417
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。