摘要:在這些文件的下載執行過程中,用戶看到的則是一片空白。頁面仍然必須等到所有代碼下載并執行完畢才能繼續渲染。
前言
kyrieliuの《高性能JavaScript》讀書筆記。
script標簽是一個很“霸道”的狠角色,它的每次出現都讓頁面等待腳本的解析和執行。也就是說,不管當前的javascript代碼是內嵌還是包含在外鏈文件中,頁面的下載和渲染都必須停下來等待腳本執行完成。
其實,script標簽的“霸道”是必須的,因為頁面的生存周期中,腳本的執行可能會修改頁面的內容。
總之,在解析和執行js的這個過程中,頁面渲染和用戶交互完全被阻塞了。
說起腳本的位置,腦海里不禁想起來那兩句真言:
css放在里
js放在前
至于why呢,舉個栗砸:
一個栗子 hello from kyrieliu.
這一段看似正常的代碼實際上有著肥腸嚴重的性能問題:在head中加載了三個js文件。
前面我有說到,js文件會阻塞頁面渲染,知道它們全部下載并執行完畢后,頁面渲染才能繼續(無情無恥無理取鬧)。
縱觀一份html文檔,用戶真正看得見的內容基本上都寫在body標簽里,也就是說,瀏覽器在解析到body標簽之前,不會渲染頁面的任何部分。現在又寫了三個腳本到head標簽里面,好嘞,這下子渲染的延遲更明顯了,用戶在打開這樣的一個頁面時,看到了what?白屏!用戶不能瀏覽頁面的內容,更無法與頁面進行交互。
第一個js文件開始下載,與此同時阻塞了頁面其他文件的下載。等呀等,ok,第一個js文件終于下載完了,第二個js按捺不住自己喜悅的心情,正要開始下載,突然,第一個js文件說:“且慢,老子還沒有完事呢”,第二個js文件嚇了一跳,站在原地不動。第一個js文件開始執行,等到執行完畢,第二個js文件才得以開始下載。
總之,每個文件必須等到前一個文件下載并執行完成才會開始下載。
在這些文件"one by one"的下載執行過程中,用戶看到的則是一片空白。
IE8/Firefox3.5/Safari 4/Chrome 2都允許并行下載js文件,也就是說,script標簽在下載外部資源時,不會阻塞其他的script標簽。
遺憾的是:
js文件的下載過程仍然會阻塞其他資源的下載,比如圖片。
頁面仍然必須等到所有js代碼下載并執行完畢才能繼續渲染。
因此,盡管瀏覽器通過允許并行下載提高了性能,但腳本阻塞仍然是一個問題。
綜上,推薦將所有的script標簽盡可能的放在body標簽的底部,以盡量減少對整個頁面渲染的影響。
既然每個script標簽初始下載時都會阻塞頁面渲染,那么我們可以通過減少頁面上script標簽的數量來改善這一情況。不光是外鏈的腳本,內嵌腳本的數量同樣也要限制(畢竟執行js代碼也會阻塞頁面的渲染)。
多于外鏈的腳本,這里的情況有一點需要額外注意的地方:考慮HTTP請求會帶來額外的性能開銷,所以下載單個100kb的文件要比下載四個25kb的文件更快。從這個角度出發,更能說明減少外鏈腳本文件的數量將會改善性能。
What u should do?合并腳本!
隨著web應用的功能越豐富,所需要的js代碼就越多,所以精簡源代碼也并不總是可行。盡管下載單個較大的js文件只產生一次HTTP請求,但這樣做卻會鎖死瀏覽器一大段時間。
為了避免這種情況,需要向頁面中逐步加載js文件,這樣做,在某種程度上來說不會阻塞瀏覽器。
HTML4為script標簽定義了一個擴展屬性:defer。Defer表明本元素所含的腳本不會修改DOM,因此代碼能安全的延遲執行。
帶有defer屬性的script標簽可以放在文檔的任何位置(不會阻塞瀏覽器的其他進程,此類文件可以與頁面中的其他資源并行下載),對應的js代碼將在頁面解析到script標簽時開始下載,但并不會執行,(onload事件被出發前)才會執行。
PS:截至這本書的第一版(2010年11月),這個屬性對IE和Firefox的支持性比較好(我的天居然有IE),如果真要投入到實際的項目中,不妨先去檢查一下瀏覽器的兼容性先~
var script = document.createElement("script"); script.type = "text/javascript"; script.src = "js_file.js"; document.getElementsByTagName("body")[0].appendChild(script);
Firefox/Opera/Chrome和Safari 3+會在script元素接收完成時出發一個load事件,所以你可以通過監聽這個事件來獲得腳本加載完成時的狀態:
script.onload = function(){ console.log("script loaded."); }
一向特立獨行的IE自然有他的另一套:觸發一個readystatechange事件。script元素提供一個readyState屬性,有以下五種取值:
"uninitialized"
"loading"
"loaded"
"interactive" 數據完成下載但尚不可用
"complete"
所以,
script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; console.log("script loaded."); } }
至此,我們得到了一個可以應用于廣泛瀏覽器的動態加載腳本用的函數:
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{ script.onload = function(){ callback(); } } }
可以這么用:
loadScript("file.js",function(){ console.log("script loaded."); });
也可以這么用:
loadScript("file_1.js",function(){ loadScript("file_2.js",function(){ loadScript("file_3.js",function(){ console.log("all files are loaded."); }); }); });XMLHttpRequest腳本注入
標題看起來很高大上的樣子,其實就是Ajax。
var xhr = new XMLHttpRequest(); xhr.open("get","file.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);
局限:跨域問題。
小結body閉合標簽之前,將所有的script標簽放到頁面底部。這樣能確保在腳本執行前頁面已經完成了渲染。
合并腳本。頁面中的script標簽越少,加載也就越快,響應也更迅速。
無阻塞下載js:
script標簽的defer屬性
動態創建script元素來下載并執行代碼
使用XHR對象下載js代碼并注入頁面中。
分享一個還算有趣的前端er:——微信公眾號:劉凱里(kkkyrieliu)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81751.html
摘要:簡單高效的自定義方式對于這些情況我們可以使用一個強大的瀏覽器插件,簡稱,中文俗稱為油猴,支持和瀏覽器。簡單幾行代碼,就可以去除大部分頁面廣告。聲明需要使用的函數。 會CSS就會去廣告~ 傳統去廣告方法的弊端 我們瀏覽網頁的時候經常不免會看到各種不想看到的廣告內容,最簡單的方案就是通過瀏覽器插件來解決,比如大名鼎鼎的AdBlock插件以及國內的各種廣告攔截助手。 但這些插件的攔截能力可...
摘要:簡單高效的自定義方式對于這些情況我們可以使用一個強大的瀏覽器插件,簡稱,中文俗稱為油猴,支持和瀏覽器。簡單幾行代碼,就可以去除大部分頁面廣告。聲明需要使用的函數。 會CSS就會去廣告~ 傳統去廣告方法的弊端 我們瀏覽網頁的時候經常不免會看到各種不想看到的廣告內容,最簡單的方案就是通過瀏覽器插件來解決,比如大名鼎鼎的AdBlock插件以及國內的各種廣告攔截助手。 但這些插件的攔截能力可...
摘要:反饋檢測到的每個人的置信度值以及檢測到的每個姿勢關鍵點。姿勢置信度這決定了姿勢判斷的整體置信度。在較高級別,這將控制回饋的姿勢較低置信度分數。只有在調整姿勢置信度得分不夠好的情況下,為了過濾掉不太準確的姿勢,該數值應該增加或減少。 文 / Dan Oved,Google Creative Lab 的自由創意技術專家,紐約大學 ITP 的研究生。編輯和插圖 / 創意技術專家 Irene Alv...
閱讀 2694·2023-04-25 17:58
閱讀 2978·2021-11-15 11:38
閱讀 2378·2021-11-02 14:48
閱讀 1184·2021-08-25 09:40
閱讀 1823·2019-08-30 15:53
閱讀 1093·2019-08-30 15:52
閱讀 1031·2019-08-30 13:55
閱讀 2436·2019-08-29 15:21