新的思考.
- CSS和JS在網(wǎng)頁中的放置順序
- 白屏和FOUC
- async和defer的作用和區(qū)別
- 網(wǎng)頁的渲染機(jī)制
CSS和JS在網(wǎng)頁中的放置順序
通常情況,人們都會在
<head></head>
(Html頭部位置)里面以<link>
來引入** Css **文件...** JavaScript **則不同,視情況而定:
通常的做法是將 JavaScript 代碼放置在 HTML 文檔的<head></head>
標(biāo)簽之間。因?yàn)?HTML 文檔是由瀏覽器從上到下依次載入的,所以將 JavaScript 代碼放置于<head></head>
標(biāo)簽之間,可以確保在需要使用腳本之前,已經(jīng)被載入(最佳做法:只放置呈現(xiàn)頁面效果實(shí)現(xiàn)類的 javascript)。
另一種方法:將 JavaScript 代碼放置于 <body></body> 之間的。這樣做的目的,是考慮到如果我們有一段 JavaScript 代碼需要操作(動作、交互等) HTML 元素。但由于 HTML 文檔是由瀏覽器從上到下依次載入的,為避免 JavaScript 代碼操作 HTML 元素時,HTML 元素還未載入而報錯(對象不存在),因此需要將這段代碼寫到 HTML 元素后面。
另外,運(yùn)用得最多的一種,是引用外部 script 的使用...跟引入外部 css 一個道理。
- 引用好處:
- 便于管理..
- 避免在 JavaScript 代碼里使用
- 避免使用難看的 CDATA
- 公共的 JavaScript 代碼可以被復(fù)用于其他 HTML 文檔,也利于 JavaScript 代碼的統(tǒng)一維護(hù)
- HTML 文檔更小,利于搜索引擎收錄
- 可以壓縮、加密單個 JavaScript 文件
- 瀏覽器可以緩存 JavaScript 文件,減少寬帶使用(當(dāng)多個頁面同時使用一個 JavaScript 文件的時候,通常只需下載一次)
- 避免使用復(fù)雜的 HTML 實(shí)體,如可以直接使用 document.write(2>1) 而無需寫作 document.write(2<1)
將 JavaScript 代碼形成為外部文件,也會增加服務(wù)器的 HTTP 請求負(fù)擔(dān),在超高并發(fā)請求的環(huán)境下,這并不是一個好的策略。另外 在引用外部 js 文件時,需注意文件的正確路徑。
- 加載異步:
<script defer src="script.js"></script>
<script async src="script.js"></script>
defer和asnyc是腳本異步加載的兩種方式。
defer,加載后續(xù)文檔元素的過程將和 script.js 的加載并行進(jìn)行(異步),但 script.js 的執(zhí)行要在所有元素解析完成之后,DOMContentLoaded 事件觸發(fā)之前完成。
async,加載和渲染后續(xù)文檔元素的過程將和 script.js 的加載與執(zhí)行并行進(jìn)行(異步)。
白屏和FOUC
白屏和FOUC(無樣式內(nèi)容閃爍)的產(chǎn)生主要與瀏覽器的渲染機(jī)制有關(guān),有的瀏覽器是等待html和css全部加載完成后再進(jìn)行渲染(白屏問題),有的瀏覽器是先顯示已加載的html內(nèi)容,等到css加載完成后重新對內(nèi)容添加樣式(FOUC問題)
白屏的產(chǎn)生
白屏的產(chǎn)生有三種情況:將css文件放在html文檔的最后、使用@import引入css(因?yàn)橥ㄟ^@import引入的css文件會被最后加載,因此也會導(dǎo)致白屏)或者將js文件放在頭部,而未使用defer或async延遲或異步加載js文件,導(dǎo)致js阻塞html和css的加載原理分析:
對于-webkit內(nèi)核的瀏覽器(IE也會產(chǎn)生),在進(jìn)行網(wǎng)頁渲染時,會同時加載html和css分別構(gòu)建DOM樹和CSSOM,等兩者都構(gòu)建完成后,再繪制渲染樹,然后將頁面顯示出來。如果在html中將css文件放置在文檔最后,那么將會導(dǎo)致CSSOM晚于DOM樹的建立,瀏覽器需要等待CSSOM建立,然后才進(jìn)行網(wǎng)頁內(nèi)容的繪制,這個等待的過程,沒有內(nèi)容顯示,就導(dǎo)致了白屏的產(chǎn)生,因此在開發(fā)中,需要將CSS放在head標(biāo)簽內(nèi),讓其與html內(nèi)容同時被加載。FOUC的產(chǎn)生
主要是由于瀏覽器先顯示已加載的html內(nèi)容,等到css加載完成后重新對內(nèi)容添加樣式導(dǎo)致的,主要代表有Firefox
async和defer的作用和區(qū)別
<pre><script src="script.js"></script>
</pre>
- 沒有 defer 或 async,瀏覽器會立即加載并執(zhí)行指定的腳本,“立即”指的是在渲染該 script 標(biāo)簽之下的文檔元素之前,也就是說不等待后續(xù)載入的文檔元素,讀到就加載并執(zhí)行。
<script async src="script.js"></script>
- 有 async,加載和渲染后續(xù)文檔元素的過程將和 script.js 的加載與執(zhí)行并行進(jìn)行(異步)。
<script defer src="myscript.js"></script>
- 有 defer,加載后續(xù)文檔元素的過程將和 script.js 的加載并行進(jìn)行(異步),但是 script.js 的執(zhí)行要在所有元素解析完成之后,DOMContentLoaded 事件觸發(fā)之前完成。
然后從實(shí)用角度來說呢,首先把所有腳本都丟到 </body> 之前是最佳實(shí)踐,因?yàn)閷τ谂f瀏覽器來說這是唯一的優(yōu)化選擇,此法可保證非腳本的其他一切元素能夠以最快的速度得到加載和解析。
網(wǎng)頁的渲染機(jī)制
瀏覽器會解析這么三個東西:
一個是HTML/SVG/XHTML,解析他們會產(chǎn)生DOM tree
CSS文件,構(gòu)建CSS Rule Tree(產(chǎn)生CSSOM:CSS object Model)
JavaScript腳本,主要通過DOM API 和CSSOM API來操作DOM樹和CSS Rule Tree解析完成后,會通過DOM Tree和CSS Rule Tree來構(gòu)建
Rendering Tree,注意:Rendering Tree并不等同于DOM Tree,因?yàn)橄駂eader和display:none相關(guān)的東西就沒有必要放在Rendering 渲染樹中了
CSS Rule Tree主要是為了將CSS Rule添加到Rendering Tree中的每一個element中,也就是DOM節(jié)點(diǎn)
然后計算每個DOM節(jié)點(diǎn)的位置,這個過程叫做layout
最后將頁面繪制出來,呈現(xiàn)引擎會遍歷Rendering Tree,由用戶界面后端層將每個節(jié)點(diǎn)繪制出來。