亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 網站 > WEB開發 > 正文

加快JavaScript加載和執行效率

2024-04-27 15:04:10
字體:
來源:轉載
供稿:網友

javaScript 在瀏覽器中的性能成為開發者所面臨的最重要的可用性問題。而這個問題又因 Javascript 的阻塞特性變的復雜,也就是說當瀏覽器在執行 JavaScript 代碼時,不能同時做其他任何事情。本文詳細介紹了如何正確的加載和執行 JavaScript 代碼,從而提高其在瀏覽器中的性能。

概覽

無論當前 JavaScript 代碼是內嵌還是在外鏈文件中,頁面的下載和渲染都必須停下來等待腳本執行完成。JavaScript 執行過程耗時越久,瀏覽器等待響應用戶輸入的時間就越長。瀏覽器在下載和執行腳本時出現阻塞的原因在于,腳本可能會改變頁面或 JavaScript 的命名空間,它們對后面頁面內容造成影響。一個典型的例子就是在頁面中使用document.write()。

JavaScript 代碼內嵌示例

<html><head>    <title>Source Example</title></head><body>    <p>    <script type="text/javascript">        document.write("Today is " + (new Date()).toDateString());    </script>    </p></body></html>

當瀏覽器遇到<script>標簽時,當前 html 頁面無從獲知 JavaScript 是否會向<p> 標簽添加內容,或引入其他元素,或甚至移除該標簽。因此,這時瀏覽器會停止處理頁面,先執行 JavaScript代碼,然后再繼續解析和渲染頁面。同樣的情況也發生在使用 src 屬性加載 JavaScript的過程中,瀏覽器必須先花時間下載外鏈文件中的代碼,然后解析并執行它。在這個過程中,頁面渲染和用戶交互完全被阻塞了。

腳本位置

HTML 4 規范指出 <script> 標簽可以放在 HTML 文檔的<head>或<body>中,并允許出現多次。web 開發人員一般習慣在 <head> 中加載外鏈的 JavaScript,接著用 <link> 標簽用來加載外鏈的 CSS 文件或者其他頁面信息。

低效率腳本位置示例

<html><head>    <title>Source Example</title>    <script type="text/javascript" src="script1.js"></script>    <script type="text/javascript" src="script2.js"></script>    <script type="text/javascript" src="script3.js"></script>    <link rel="stylesheet" type="text/css" href="styles.css"></head><body>    <p>Hello world!</p></body></html>

然而這種常規的做法卻隱藏著嚴重的性能問題。在清單 2 的示例中,當瀏覽器解析到 <script> 標簽(第 4 行)時,瀏覽器會停止解析其后的內容,而優先下載腳本文件,并執行其中的代碼,這意味著,其后的 styles.css 樣式文件和<body>標簽都無法被加載,由于<body>標簽無法被加載,那么頁面自然就無法渲染了。因此在該 JavaScript 代碼完全執行完之前,頁面都是一片空白。

由于腳本會阻塞頁面其他資源的下載,因此推薦將所有<script>標簽盡可能放到<body>標簽的底部,以盡量減少對整個頁面下載的影響。

推薦的代碼放置位置示例

<html><head>    <title>Source Example</title>    <link rel="stylesheet" type="text/css" href="styles.css"></head><body>    <p>Hello world!</p>    <!-- Example of efficient script positioning -->    <script type="text/javascript" src="script1.js"></script>    <script type="text/javascript" src="script2.js"></script>    <script type="text/javascript" src="script3.js"></script></body></html>

這段代碼展示了在 HTML 文檔中放置<script>標簽的推薦位置。盡管腳本下載會阻塞另一個腳本,但是頁面的大部分內容都已經下載完成并顯示給了用戶,因此頁面下載不會顯得太慢。這是優化 JavaScript 的首要規則:將腳本放在底部。

組織腳本

由于每個 <script> 標簽初始下載時都會阻塞頁面渲染,所以減少頁面包含的 <script> 標簽數量有助于改善這一情況。這不僅針對外鏈腳本,內嵌腳本的數量同樣也要限制。瀏覽器在解析 HTML 頁面的過程中每遇到一個 <script> 標簽,都會因執行腳本而導致一定的延時,因此最小化延遲時間將會明顯改善頁面的總體性能。

這個問題在處理外鏈 JavaScript 文件時略有不同??紤]到 HTTP 請求會帶來額外的性能開銷,因此下載單個 100Kb 的文件將比下載 5 個 20Kb 的文件更快。也就是說,減少頁面中外鏈腳本的數量將會改善性能。

通常一個大型網站或應用需要依賴數個 JavaScript 文件。您可以把多個文件合并成一個,這樣只需要引用一個 <script> 標簽,就可以減少性能消耗。文件合并的工作可通過離線的打包工具或者一些實時的在線服務來實現。

需要特別提醒的是,把一段內嵌腳本放在引用外鏈樣式表的 <link> 之后會導致頁面阻塞去等待樣式表的下載。這樣做是為了確保內嵌腳本在執行時能獲得最精確的樣式信息。因此,建議不要把內嵌腳本緊跟在 <link> 標簽后面。

無阻塞的腳本

減少 JavaScript 文件大小并限制 HTTP 請求數在功能豐富的 Web 應用或大型網站上并不總是可行。Web 應用的功能越豐富,所需要的 JavaScript 代碼就越多,盡管下載單個較大的 JavaScript 文件只產生一次 HTTP 請求,卻會鎖死瀏覽器的一大段時間。為避免這種情況,需要通過一些特定的技術向頁面中逐步加載 JavaScript 文件,這樣做在某種程度上來說不會阻塞瀏覽器。

無阻塞腳本的秘訣在于,在頁面加載完成后才加載 JavaScript 代碼。這就意味著在 window 對象的 onload 事件觸發后再下載腳本。有多種方式可以實現這一效果。

延遲加載腳本

HTML 4 為 <script> 標簽定義了一個擴展屬性: defer 。 Defer 屬性指明本元素所含的腳本不會修改 DOM,因此代碼能安全地延遲執行。 defer 屬性只被 IE 4 和 Firefox 3.5 更高版本的瀏覽器所支持,所以它不是一個理想的跨瀏覽器解決方案。在其他瀏覽器中, defer 屬性會被直接忽略,因此 <script> 標簽會以默認的方式處理,也就是說會造成阻塞。然而,如果您的目標瀏覽器支持的話,這仍然是個有用的解決方案。

defer 屬性使用方法示例

<script type="text/javascript" src="script1.js" defer></script>

帶有 defer 屬性的 <script> 標簽可以放置在文檔的任何位置。對應的 JavaScript 文件將在頁面解析到 <script> 標簽時開始下載,但不會執行,直到 DOM 加載完成,即 onload 事件觸發前才會被執行。當一個帶有 defer 屬性的 JavaScript 文件下載時,它不會阻塞瀏覽器的其他進程,因此這類文件可以與其他資源文件一起并行下載。

任何帶有 defer 屬性的 <script> 元素在 DOM 完成加載之前都不會被執行,無論內嵌或者是外鏈腳本都是如此。清單 5 的例子展示了 defer 屬性如何影響腳本行為:

defer 屬性對腳本行為的影響

<html><head>    <title>Script Defer Example</title></head><body>    <script type="text/javascript" defer>        alert("defer");    </script>    <script type="text/javascript">        alert("script");    </script>    <script type="text/javascript">        window.onload = function(){            alert("load");        };    </script></body></html>

這段代碼在頁面處理過程中彈出三次對話框。不支持 defer 屬性的瀏覽器的彈出順序是:“defer”、“script”、“load”。而在支持 defer 屬性的瀏覽器上,彈出的順序則是:“script”、“defer”、“load”。請注意,帶有 defer 屬性的 <script> 元素不是跟在第二個后面執行,而是在 onload 事件被觸發前被調用。

如果您的目標瀏覽器只包括 Internet Explorer 和 Firefox 3.5,那么 defer 腳本確實有用。如果您需要支持跨領域的多種瀏覽器,那么還有更一致的實現方式。

HTML 5 為 <script> 標簽定義了一個新的擴展屬性: async 。它的作用和 defer 一樣,能夠異步地加載和執行腳本,不因為加載腳本而阻塞頁面的加載。但是有一點需要注意,在有 async 的情況下,JavaScript 腳本一旦下載好了就會執行,所以很有可能不是按照原本的順序來執行的。如果 JavaScript 腳本前后有依賴性,使用 async 就很有可能出現錯誤。

動態腳本元素

文檔對象模型(DOM)允許您使用 JavaScript 動態創建 HTML 的幾乎全部文檔內容。 <script> 元素與頁面其他元素一樣,可以非常容易地通過標準 DOM 函數創建:

通過標準 DOM 函數創建<script>元素

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

新的 <script> 元素加載 script1.js 源文件。此文件當元素添加到頁面之后立刻開始下載。此技術的重點在于:無論在何處啟動下載,文件的下載和運行都不會阻塞其他頁面處理過程。您甚至可以將這些代碼放在 <head> 部分而不會對其余部分的頁面代碼造成影響(除了用于下載文件的 HTTP 連接)。

當文件使用動態腳本節點下載時,返回的代碼通常立即執行(除了 Firefox 和 Opera,他們將等待此前的所有動態腳本節點執行完畢)。當腳本是“自運行”類型時,這一機制運行正常,但是如果腳本只包含供頁面其他腳本調用調用的接口,則會帶來問題。這種情況下,您需要跟蹤腳本下載完成并是否準備妥善。可以使用動態 <script> 節點發出事件得到相關信息。

Firefox、Opera, Chorme 和 Safari 3+會在 <script> 節點接收完成之后發出一個 onload 事件。您可以監聽這一事件,以得到腳本準備好的通知:

通過監聽 onload 事件加載 JavaScript 腳本

var script = document.createElement ("script")script.type = "text/javascript";//Firefox, Opera, Chrome, Safari 3+script.onload = function(){    alert("Script loaded!");};script.src = "script1.js";document.getElementsByTagName("head")[0].appendChild(script);

Internet Explorer 支持另一種實現方式,它發出一個 readystatechange 事件。 <script> 元素有一個 readyState 屬性,它的值隨著下載外部文件的過程而改變。 readyState 有五種取值:

微軟文檔上說,在 <script> 元素的生命周期中, readyState 的這些取值不一定全部出現,但并沒有指出哪些取值總會被用到。實踐中,我們最感興趣的是“loaded”和“complete”狀態。Internet Explorer 對這兩個 readyState 值所表示的最終狀態并不一致,有時 <script> 元素會得到“loader”卻從不出現“complete”,但另外一些情況下出現“complete”而用不到“loaded”。最安全的辦法就是在 readystatechange 事件中檢查這兩種狀態,并且當其中一種狀態出現時,刪除 readystatechange 事件句柄(保證事件不會被處理兩次):

通過檢查 readyState 狀態加載 JavaScript 腳本

var script = document.createElement("script")script.type = "text/javascript";//Internet Explorerscript.onreadystatechange = function(){     if (script.readyState == "loaded" || script.readyState == "complete"){           script.onreadystatechange = null;           alert("Script loaded.");     }};script.src = "script1.js";document.getElementsByTagName("head")[0].appendChild(script);

大多數情況下,您希望調用一個函數就可以實現 JavaScript 文件的動態加載。下面的函數封裝了標準實現和 IE 實現所需的功能:

通過函數進行封裝

function loadScript(url, callback){    var script = document.createElement ("script")    script.type = "text/javascript";    if (script.readyState){ //IE        script.onreadystatechange = function(){            if (script.readyState == "loaded" || script.readyState == "complete"){                script.onreadystatechange = null;                callback();            }        };    } else { //Others        script.onload = function(){            callback();        };    }    script.src = url;    document.getElementsByTagName("head")[0].appendChild(script);}

此函數接收兩個參數:JavaScript 文件的 URL,和一個當 JavaScript 接收完成時觸發的回調函數。屬性檢查用于決定監視哪種事件。最后一步,設置 src 屬性,并將 <script> 元素添加至頁面。此 loadScript() 函數使用方法如下:

loadScript()函數使用方法

loadScript("script1.js", function(){    alert("File is loaded!");});

您可以在頁面中動態加載很多 JavaScript 文件,但要注意,瀏覽器不保證文件加載的順序。所有主流瀏覽器之中,只有 Firefox 和 Opera 保證腳本按照您指定的順序執行。其他瀏覽器將按照服務器返回它們的次序下載并運行不同的代碼文件。您可以將下載操作串聯在一起以保證他們的次序,如下:

通過 loadScript()函數加載多個 JavaScript 腳本

loadScript("script1.js", function(){    loadScript("script2.js", function(){        loadScript("script3.js", function(){            alert("All files are loaded!");        });    });});

此代碼等待 script1.js 可用之后才開始加載 script2.js,等 script2.js 可用之后才開始加載 script3.js。雖然此方法可行,但如果要下載和執行的文件很多,還是有些麻煩。如果多個文件的次序十分重要,更好的辦法是將這些文件按照正確的次序連接成一個文件。獨立文件可以一次性下載所有代碼(由于這是異步進行的,使用一個大文件并沒有什么損失)。

動態腳本加載是非阻塞 JavaScript 下載中最常用的模式,因為它可以跨瀏覽器,而且簡單易用。

使用 xmlHttPRequest(XHR)對象

此技術首先創建一個 XHR 對象,然后下載 JavaScript 文件,接著用一個動態 <script> 元素將 JavaScript 代碼注入頁面。清單 12 是一個簡單的例子:

通過 XHR 對象加載 JavaScript 腳本

var xhr = new xmlhttpRequest();xhr.open("get", "script1.js", true);xhr.onreadystatechange = function(){    if (xhr.readyState == 4){        if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){            var script = document.createElement ("script");            script.type = "text/javascript";            script.text = xhr.responseText;            document.body.appendChild(script);        }    }};xhr.send(null);

此代碼向服務器發送一個獲取 script1.js 文件的 GET 請求。 onreadystatechange 事件處理函數檢查 readyState 是不是 4,然后檢查 HTTP 狀態碼是不是有效(2XX 表示有效的回應,304 表示一個緩存響應)。如果收到了一個有效的響應,那么就創建一個新的 <script> 元素,將它的文本屬性設置為從服務器接收到的 responseText 字符串。這樣做實際上會創建一個帶有內聯代碼的 <script> 元素。一旦新 <script> 元素被添加到文檔,代碼將被執行,并準備使用。

這種方法的主要優點是,您可以下載不立即執行的 JavaScript 代碼。由于代碼返回在 <script> 標簽之外(換句話說不受 <script> 標簽約束),它下載后不會自動執行,這使得您可以推遲執行,直到一切都準備好了。另一個優點是,同樣的代碼在所有現代瀏覽器中都不會引發異常。

此方法最主要的限制是:JavaScript 文件必須與頁面放置在同一個域內,不能從 CDN 下載(CDN 指"內容投遞網絡(Content Delivery Network)",所以大型網頁通常不采用 XHR 腳本注入技術。

總結

減少 JavaScript 對性能的影響有以下幾種方法:

通過以上策略,可以在很大程度上提高那些需要使用大量 JavaScript 的 Web 網站和應用的實際性能。

function loadJs(url, callback, charset) {    var head = document.getElementsByTagName("head")[0];    var script = document.createElement("script");    if ( !!charset) script.charset = "utf-8";    script.src = url;    script.onload = script.onreadystatechange = function() {        var f = script.readyState;        if (f && f != "loaded" && f != "complete") return;        script.onload = script.onreadystatechange = null;        head.removeChild(script) if (callback) {            callback() || callback        };    };    head.appendChild(script);}
// js同步加載function getScripts(i, linkArray, fn) {    env || getEnv();    var script = document.createElement('script');    script.type = 'text/javascript';    script.src = linkArray[i];    var head = document.head || document.getElementsByTagName('head')[0];    head.appendChild(script);    if (env.ie && 'onreadystatechange' in script && !('draggable' in script)){ //ie瀏覽器使用以下方式加載        script.onreadystatechange = function () {          if (/loaded|complete/.test(script.readyState)) {            script.onreadystatechange = null;            if(i === linkArray.length-1) {                if (fn) {                    fn();                }            } else {                getScripts(++i, linkArray, fn);            }          }        };    }else{        script.onload = function() {            if(i === linkArray.length-1) {                if (fn) {                    fn();                }            } else {                getScripts(++i, linkArray, fn);            }        };    }}
// js存在依賴關系 依次加載getScripts(0, [    'http://caibaojian.com/demo/base.js',    'http://caibaojian.com/demo/reset.js'], function() {     alert('callback');});


上一篇:css基礎

下一篇:純css實現對白框

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一本一道久久a久久精品逆3p| 国产精品 欧美在线| 国产精品视频网| 欧美黑人又粗大| 国产午夜精品麻豆| 粗暴蹂躏中文一区二区三区| 亚洲精品国产精品国自产观看浪潮| 国产午夜精品视频免费不卡69堂| 欧美一性一乱一交一视频| 精品久久久久久久久久ntr影视| 欧美丰满少妇xxxxx| 国产国产精品人在线视| 国产欧美日韩精品丝袜高跟鞋| 国产91精品不卡视频| 亚洲精品日韩久久久| 成人中文字幕+乱码+中文字幕| 国产精品美女av| 亚洲四色影视在线观看| 中文日韩在线观看| 青青在线视频一区二区三区| 日韩欧美在线视频| 欧美在线免费视频| 正在播放欧美一区| 欧美成人免费大片| 久久久精品日本| 国产va免费精品高清在线观看| 亚洲精品美女免费| 欧美中文字幕在线播放| 91久久精品国产91久久性色| 中文字幕在线成人| 亚洲天堂av网| 欧美久久精品一级黑人c片| 欧美最猛性xxxxx(亚洲精品)| 久久成人在线视频| 97视频在线观看亚洲| 欧美性xxxxx极品娇小| 国产精品九九久久久久久久| 91亚洲一区精品| 欧美一级在线播放| 97不卡在线视频| 欧美最顶级的aⅴ艳星| 91免费看片网站| 国产成人精彩在线视频九色| 亚洲精品720p| 爽爽爽爽爽爽爽成人免费观看| 亚洲成人教育av| 神马久久久久久| 国内外成人免费激情在线视频网站| 日韩美女在线观看| 日韩电影大片中文字幕| 色偷偷噜噜噜亚洲男人的天堂| 中文字幕九色91在线| 久久色精品视频| 国产精品一区二区三区久久久| 亚洲毛片一区二区| 国产成人精彩在线视频九色| 91免费观看网站| 国产美女精品视频免费观看| 日韩va亚洲va欧洲va国产| 色婷婷综合久久久久| 亚洲一区二区三区sesese| 久久久久久中文| 久久精品成人欧美大片| 2019精品视频| 色综合久久88色综合天天看泰| 久久久久久久久国产精品| 欧美裸体xxxx| 在线电影欧美日韩一区二区私密| 欧美插天视频在线播放| 日韩小视频在线| 91在线视频一区| 亚洲午夜精品视频| 日韩av在线免费看| www高清在线视频日韩欧美| 亚洲欧美激情在线视频| 成人精品一区二区三区| 日韩av免费在线看| 欧美高清在线视频观看不卡| 国产精品福利在线观看| 国产一区二区三区直播精品电影| 亚洲a∨日韩av高清在线观看| 中文精品99久久国产香蕉| 欧美日韩国产第一页| 91久久久国产精品| 日韩av在线免费观看一区| 日韩av电影免费观看高清| 一区二区三区美女xx视频| 亚洲一区二区福利| 美女少妇精品视频| 日韩欧美中文字幕在线播放| 亚洲第一精品夜夜躁人人爽| 国产午夜精品视频免费不卡69堂| 色综合影院在线| 久热爱精品视频线路一| 久久久久久久久久久久av| 丝袜美腿亚洲一区二区| 欧美理论在线观看| 亚洲成色999久久网站| 欧美精品成人91久久久久久久| 国产丝袜高跟一区| 欧美夫妻性生活xx| 综合网日日天干夜夜久久| 日韩精品免费综合视频在线播放| 最新69国产成人精品视频免费| 4388成人网| 97欧美精品一区二区三区| 欧美电影在线观看高清| 欧美激情精品久久久久久变态| 亚洲人成绝费网站色www| 欧美有码在线视频| 国产有码一区二区| 日韩电影中文字幕| 高清欧美性猛交| 亚洲一区国产精品| 性欧美xxxx交| 高跟丝袜欧美一区| 最近2019免费中文字幕视频三| 日韩精品视频免费| 最近中文字幕日韩精品| 中文字幕精品一区二区精品| 精品国产鲁一鲁一区二区张丽| 久久艳片www.17c.com| 蜜月aⅴ免费一区二区三区| 欧美噜噜久久久xxx| 亚洲va欧美va在线观看| 精品视频久久久久久| 成人伊人精品色xxxx视频| www.久久久久久.com| 欧美日韩在线看| 中文字幕精品一区久久久久| 91精品国产综合久久男男| 国产精品吊钟奶在线| 国模精品一区二区三区色天香| 欧美精品第一页在线播放| 成人激情在线播放| 欧美精品做受xxx性少妇| 91精品久久久久久久久久久久久| 久久人人爽亚洲精品天堂| 欧美限制级电影在线观看| 97人人模人人爽人人喊中文字| 欧美日韩在线一区| 久久久久这里只有精品| 国产精品盗摄久久久| 一区二区三区视频在线| 538国产精品视频一区二区| 川上优av一区二区线观看| 国产成人涩涩涩视频在线观看| 欧美壮男野外gaytube| 国产在线视频2019最新视频| 国产精品久久国产精品99gif| 综合网日日天干夜夜久久| 国产精品久久久久7777婷婷| 久久天天躁夜夜躁狠狠躁2022| 亚洲美女喷白浆| 日韩欧美亚洲国产一区| 欧美久久精品午夜青青大伊人| 亚洲成人教育av| 亚洲国产日韩欧美综合久久| 欧美孕妇性xx| 日韩一级裸体免费视频| 人人做人人澡人人爽欧美| 久久精品2019中文字幕| 国产精品网址在线| 国产精品视频成人|