rem實現網頁自適應螢幕大小的小結
(1)在chrome瀏覽器的開發過程中,我們會看到network面板中有這兩個數值,分別對應網 絡請求上的標誌線,這兩個時間數值分別代表什麼?
(2)我們一再強調將css放在頭部,將js檔案放在尾部,這樣有利於優化頁面的效能,為什麼這種方式能夠優化效能?
(3)在用jquery的時候,我們一般都會將函式呼叫寫在ready方法內,這是什麼原理?
首先看一下
DOMContentLoaded顧名思義,就是dom內容載入完畢。那什麼是dom內容載入完畢呢?我們從開啟一個網頁說起。當輸入一個URL,頁面的展示首先是空白的,然後過一會,頁面會展示出內容,但是頁面的有些資源比如說圖片資源還無法看到,此時頁面是可以正常的互動,過一段時間後,圖片才完成顯示在頁面。從頁面空白到展示出頁面內容,會觸發
這時候問題又來了,什麼是HTML文件被載入和解析完成。要解決這個問題,我們就必須瞭解瀏覽器渲染原理。
當我們在瀏覽器地址輸入URL時,瀏覽器會發送請求到伺服器,伺服器將請求的HTML文件傳送回瀏覽器,瀏覽器將文件下載下來後,便開始從上到下解析,解析完成之後,會生成DOM。如果頁面中有css,會根據css的內容形成CSSOM,然後DOM和CSSOM會生成一個渲染樹,最後瀏覽器會根據渲染樹的內容計算出各個節點在頁面中的確切大小和位置,並將其繪製在瀏覽器上。
下面就是頁面載入和解析過程中,瀏覽器的一個快照
上面我們看到在解析html的過程中,
同時javascript的執行會受到標籤前面樣式檔案的影響。如果在標籤前面有樣式檔案,需要樣式檔案載入並解析完畢後才執行指令碼。這是因為javascript可以查詢物件的樣式。
這裡需要注意一點,在現在瀏覽器中,為了減緩渲染被阻塞的情況,現代的瀏覽器都使用了猜測預載入。當解析被阻塞的時候,
在這裡我們可以明確DOMContentLoaded所計算的時間,當文件中沒有指令碼時,瀏覽器解析完文件便能觸發 DOMContentLoaded 事件;如果文件中包含指令碼,則指令碼會阻塞文件的解析,而指令碼需要等位於指令碼前面的css載入完才能執行。在任何情況下,DOMContentLoaded 的觸發不需要等待圖片等其他資源載入完成。
接下來,我們來說說load,頁面上所有的資源(圖片,音訊,視訊等)被載入以後才會觸發load事件,簡單來說,頁面的load事件會在DOMContentLoaded被觸發之後才觸發。
我們在 jQuery 中經常使用的 $(document).ready(function() { // ...程式碼... }); 其實監聽的就是 DOMContentLoaded 事件,而$(document).load(function() { // ...程式碼... }); 監聽的是 load 事件。在用jquery的時候,我們一般都會將函式呼叫寫在ready方法內,就是頁面被解析後,我們就可以訪問整個頁面的所有dom元素,可以縮短頁面的可互動時間,提高整個頁面的體驗。
下面我們在來看看如何實現這兩個函式
1、onload事件
onload事件所有的瀏覽器都支援,所以我們不需要什麼相容,只要通過呼叫
window.onload = function(){ }
2、DOMContentLoaded 事件
DOMContentLoaded不同的瀏覽器對其支援不同,所以在實現的時候我們需要做不同瀏覽器的相容。
1)支援DOMContentLoaded事件的,就使用DOMContentLoaded事件;
2)IE6、IE7不支援DOMContentLoaded,但它支援onreadystatechange事件,該事件的目的是提供與文件或元素的載入狀態有關的資訊。
3) 更低的ie還有個特有的方法doScroll, 通過間隔呼叫:document.documentElement.doScroll("left");
可以檢測DOM是否載入完成。 當頁面未載入完成時,該方法會報錯,直到doScroll不再報錯時,就代表DOM載入完成了。該方法更接近DOMContentLoaded的實現。
function ready(fn){ if(document.addEventListener) { document.addEventListener('DOMContentLoaded', function() { document.removeEventListener('DOMContentLoaded',arguments.callee, false); fn(); }, false); } // 如果IE else if(document.attachEvent) { // 確保當頁面是在iframe中載入時,事件依舊會被安全觸發 document.attachEvent('onreadystatechange', function() { if(document.readyState == 'complete') { document.detachEvent('onreadystatechange', arguments.callee); fn(); } }); // 如果是IE且頁面不在iframe中時,輪詢呼叫doScroll 方法檢測DOM是否載入完畢 if(document.documentElement.doScroll && typeof window.frameElement === "undefined") { try{ document.documentElement.doScroll('left'); } catch(error){ return setTimeout(arguments.callee, 20); }; fn(); } } };
最後我們來回答這個問題:我們為什麼一再強調將css放在頭部,將js檔案放在尾部
在面試的過程中,經常會有人在回答頁面的優化中提到將js放到body標籤底部,原因是因為瀏覽器生成Dom樹的時候是一行一行讀HTML程式碼的,script標籤放在最後面就不會影響前面的頁面的渲染。那麼問題來了,既然Dom樹完全生成好後頁面才能渲染出來,瀏覽器又必須讀完全部HTML才能生成完整的Dom樹,script標籤不放在body底部是不是也一樣,因為dom樹的生成需要整個文件解析完畢。
我們再來看一下chrome在頁面渲染過程中的,綠色標誌線是First Paint的時間。納尼,為什麼會出現firstpaint,頁面的paint不是在渲染樹生成之後嗎?其實現代瀏覽器為了更好的使用者體驗,渲染引擎將嘗試儘快在螢幕上顯示的內容。它不會等到所有HTML解析之前開始構建和佈局渲染樹。部分的內容將被解析並顯示。也就是說瀏覽器能夠渲染不完整的dom樹和cssom,儘快的減少白屏的時間。假如我們將js放在header,js將阻塞解析dom,dom的內容會影響到First Paint,導致First Paint延後。所以說我們會將js放在後面,以減少First Paint的時間,但是不會減少DOMContentLoaded被觸發的時間。