(1)在chrome瀏覽器的開發(fā)過程中,,我們會看到network面板中有這兩個數(shù)值,,分別對應(yīng)網(wǎng) 絡(luò)請求上的標(biāo)志線,這兩個時間數(shù)值分別代表什么,? (2)我們一再強(qiáng)調(diào)將css放在頭部,,將js文件放在尾部,這樣有利于優(yōu)化頁面的性能,,為什么這種方式能夠優(yōu)化性能,? (3)在用jquery的時候,我們一般都會將函數(shù)調(diào)用寫在ready方法內(nèi),,這是什么原理,? 首先看一下 DOMContentLoaded顧名思義,就是dom內(nèi)容加載完畢,。那什么是dom內(nèi)容加載完畢呢,?我們從打開一個網(wǎng)頁說起。當(dāng)輸入一個URL,,頁面的展示首先是空白的,,然后過一會,,頁面會展示出內(nèi)容,但是頁面的有些資源比如說圖片資源還無法看到,,此時頁面是可以正常的交互,,過一段時間后,圖片才完成顯示在頁面,。從頁面空白到展示出頁面內(nèi)容,,會觸發(fā)DOMContentLoaded事件。而這段時間就是HTML文檔被加載和解析完成,。 這時候問題又來了,什么是HTML文檔被加載和解析完成,。要解決這個問題,,我們就必須了解瀏覽器渲染原理。 當(dāng)我們在瀏覽器地址輸入URL時,,瀏覽器會發(fā)送請求到服務(wù)器,,服務(wù)器將請求的HTML文檔發(fā)送回瀏覽器,瀏覽器將文檔下載下來后,,便開始從上到下解析,,解析完成之后,會生成DOM,。如果頁面中有css,,會根據(jù)css的內(nèi)容形成CSSOM,然后DOM和CSSOM會生成一個渲染樹,,最后瀏覽器會根據(jù)渲染樹的內(nèi)容計(jì)算出各個節(jié)點(diǎn)在頁面中的確切大小和位置,,并將其繪制在瀏覽器上。
下面就是頁面加載和解析過程中,,瀏覽器的一個快照
上面我們看到在解析html的過程中,,html的解析會被中斷,這是因?yàn)?/span>javascript會阻塞dom的解析,。當(dāng)解析過程中遇到<script>標(biāo)簽的時候,,便會停止解析過程,轉(zhuǎn)而去處理腳本,,如果腳本是內(nèi)聯(lián)的,,瀏覽器會先去執(zhí)行這段內(nèi)聯(lián)的腳本,如果是外鏈的,,那么先會去加載腳本,,然后執(zhí)行。在處理完腳本之后,,瀏覽器便繼續(xù)解析HTML文檔,。 同時javascript的執(zhí)行會受到標(biāo)簽前面樣式文件的影響,。如果在標(biāo)簽前面有樣式文件,需要樣式文件加載并解析完畢后才執(zhí)行腳本,。這是因?yàn)?/span>javascript可以查詢對象的樣式,。 這里需要注意一點(diǎn),在現(xiàn)在瀏覽器中,,為了減緩渲染被阻塞的情況,,現(xiàn)代的瀏覽器都使用了猜測預(yù)加載。當(dāng)解析被阻塞的時候,,瀏覽器會有一個輕量級的HTML(或CSS)掃描器(scanner)繼續(xù)在文檔中掃描,,查找那些將來可能能夠用到的資源文件的url,在渲染器使用它們之前將其下載下來,。 在這里我們可以明確DOMContentLoaded所計(jì)算的時間,,當(dāng)文檔中沒有腳本時,瀏覽器解析完文檔便能觸發(fā) DOMContentLoaded 事件,;如果文檔中包含腳本,,則腳本會阻塞文檔的解析,而腳本需要等位于腳本前面的css加載完才能執(zhí)行,。在任何情況下,,DOMContentLoaded 的觸發(fā)不需要等待圖片等其他資源加載完成。 接下來,,我們來說說load,,頁面上所有的資源(圖片,音頻,,視頻等)被加載以后才會觸發(fā)load事件,,簡單來說,頁面的load事件會在DOMContentLoaded被觸發(fā)之后才觸發(fā),。 我們在 jQuery 中經(jīng)常使用的 $(document).ready(function() { // ...代碼... }); 其實(shí)監(jiān)聽的就是 DOMContentLoaded 事件,,而 $(document).load(function() { // ...代碼... }); 監(jiān)聽的是 load 事件。在用jquery的時候,,我們一般都會將函數(shù)調(diào)用寫在ready方法內(nèi),,就是頁面被解析后,我們就可以訪問整個頁面的所有dom元素,,可以縮短頁面的可交互時間,,提高整個頁面的體驗(yàn)。 下面我們在來看看如何實(shí)現(xiàn)這兩個函數(shù) 1,、onload事件 onload事件所有的瀏覽器都支持,,所以我們不需要什么兼容,只要通過調(diào)用 window.onload = function(){
}
2、DOMContentLoaded 事件 DOMContentLoaded不同的瀏覽器對其支持不同,,所以在實(shí)現(xiàn)的時候我們需要做不同瀏覽器的兼容,。 1)支持DOMContentLoaded事件的,就使用DOMContentLoaded事件,; 2)IE6,、IE7不支持DOMContentLoaded,但它支持onreadystatechange事件,,該事件的目的是提供與文檔或元素的加載狀態(tài)有關(guān)的信息,。 3) 更低的ie還有個特有的方法doScroll, 通過間隔調(diào)用:document.documentElement.doScroll("left"); 可以檢測DOM是否加載完成,。 當(dāng)頁面未加載完成時,,該方法會報錯,直到doScroll不再報錯時,,就代表DOM加載完成了,。該方法更接近DOMContentLoaded的實(shí)現(xiàn)。
function ready(fn){ if(document.addEventListener) { document.addEventListener('DOMContentLoaded', function() { document.removeEventListener('DOMContentLoaded',arguments.callee, false); fn(); }, false); } // 如果IE else if(document.attachEvent) { // 確保當(dāng)頁面是在iframe中加載時,,事件依舊會被安全觸發(fā) document.attachEvent('onreadystatechange', function() { if(document.readyState == 'complete') { document.detachEvent('onreadystatechange', arguments.callee); fn(); } }); // 如果是IE且頁面不在iframe中時,輪詢調(diào)用doScroll 方法檢測DOM是否加載完畢 if(document.documentElement.doScroll && typeof window.frameElement === "undefined") { try{ document.documentElement.doScroll('left'); } catch(error){ return setTimeout(arguments.callee, 20); }; fn(); } } };
最后我們來回答這個問題:我們?yōu)槭裁匆辉購?qiáng)調(diào)將css放在頭部,,將js文件放在尾部 在面試的過程中,,經(jīng)常會有人在回答頁面的優(yōu)化中提到將js放到body標(biāo)簽底部,原因是因為瀏覽器生成Dom樹的時候是一行一行讀HTML代碼的,,script標(biāo)簽放在最后面就不會影響前面的頁面的渲染,。那么問題來了,既然Dom樹完全生成好后頁面才能渲染出來,,瀏覽器又必須讀完全部HTML才能生成完整的Dom樹,,script標(biāo)簽不放在body底部是不是也一樣,因?yàn)?/span>dom樹的生成需要整個文檔解析完畢,。
我們再來看一下chrome在頁面渲染過程中的,,綠色標(biāo)志線是First Paint的時間。納尼,,為什么會出現(xiàn)firstpaint,,頁面的paint不是在渲染樹生成之后嗎?其實(shí)現(xiàn)代瀏覽器為了更好的用戶體驗(yàn),渲染引擎將嘗試盡快在屏幕上顯示的內(nèi)容,。它不會等到所有HTML解析之前開始構(gòu)建和布局渲染樹,。部分的內(nèi)容將被解析并顯示。也就是說瀏覽器能夠渲染不完整的dom樹和cssom,,盡快的減少白屏的時間,。假如我們將js放在header,js將阻塞解析dom,dom的內(nèi)容會影響到First Paint,,導(dǎo)致First Paint延后,。所以說我們會將js放在后面,以減少First Paint的時間,,但是不會減少DOMContentLoaded被觸發(fā)的時間,。
|
|
來自: leowong1987 > 《待分類》