簡單介紹 JavaScript的發(fā)展歷史
- JavaScript 最初是在1994年,網景公司的Navigator瀏覽器,需要一種可以嵌入網頁的腳本語言,用來控制瀏覽器的行為,在客戶端完成一些功能。不需要很強大,語法最好簡單點,容易學習和部署。Java能勝任,但是殺雞不需要牛刀。浪費資源。
- 因此在1995年,雇傭了布蘭登·艾克,負責開發(fā)期望的網頁腳本語言。于是十天后,在1995年5月,誕生了JavaScript的第一版。
- 一開始名字是叫做,Mocha,為了蹭熱點,雙方也為了合作共贏,于是網景公司和Sun公司達成協議,改名為 JavaScript。
- 在發(fā)展了一段時間后。微軟公司在1996年,模仿JavaScript開發(fā)了一種類似的語言,取名為JScript。這一行為,使得網景公司不再獨自主導瀏覽器腳本語言。
- 1996年,網景公司覺得微軟這樣子發(fā)展不行,對自己太不利,因此找到了國際標準化組織,ECMA, 希望能把自己的JavaScript指定為國際標準。
- 1997年,第一版的標準文件出來,但是名字不是JavaScript,而是叫做ECMA,一方面JavaScript是注冊商標,另一方面,ECMA也要掛個自己的名字,畢竟是自己團隊建立的標準,所以叫做ECMAScript。
- 此后幾年,ECMAScript逐步更新到了2015年的 5.1版本,并且成為了ISO國際標準。到了2012年底,所有的主要瀏覽器都已經支持ECMAScript5.1版的全部功能。
- 2015年,ECMASCript 6 正式發(fā)布,更名為ECMAScript 2015。
- 2016年, 已經出現了 ECMAScript 7 這是目前最新的版本。
介紹瀏覽器的渲染機制
- 解析HTML以構建DOM樹:渲染引擎開始解析HTML文檔,轉換樹中的html標簽或js生成的標簽到DOM節(jié)點,它被稱為 -- 內容樹。
- 構建渲染樹:解析CSS(包括外部CSS文件和樣式元素以及js生成的樣式),根據CSS選擇器計算出節(jié)點的樣式,創(chuàng)建另一個樹 —- 渲染樹。
- 布局渲染樹: 從根節(jié)點遞歸調用,計算每一個元素的大小、位置等,給每個節(jié)點所應該出現在屏幕上的精確坐標。
- 繪制渲染樹: 遍歷渲染樹,每個節(jié)點將使用UI后端層來繪制

瀏覽器渲染流程圖
瀏覽器的工作原理,可參考How browsers work
樣式、JS 在 HTML 中如何放置?
使用 link 標簽將樣式表放在頂部
將JS放在底部
原因如下:
- 腳本會阻塞后面內容的呈現
- 腳本會阻塞其后組件的下載
解釋白屏和 FOUC
- 白屏就是,瀏覽器窗口中,無任何內容,呈現白色空白。
- FOUC,全稱是 Flash of Unstyled Content,叫做無樣式內容閃爍。
以上兩種現象,存在于不同瀏覽器的不同加載機制上。
- 白屏,如chrome瀏覽器,當腳本阻塞,或者認為設定不同加載延遲時間。會呈現白屏狀態(tài),以等待相應內容的加載。
- 而FOUC, 比如Firefox瀏覽器,如果css樣式被延遲加載或者阻塞,不會影響到前面的html dom 的展現,但是會出現無樣式狀態(tài)。
介紹下 repaint和 reflow的概念
首先,要明白的是,repaint,和reflow,都是瀏覽器內部的處理機制。你無法該表瀏覽器的處理行為, 但是你可以改變自己的代碼,從而在瀏覽器的機制下,寫出更好的代碼。
- reflow:DOM中每個元素都有自己的盒模型,這些都需要瀏覽器根據已經默認和認為定義的樣式,來計算每個元素應該安放的位置,這個過程就是reflow。
- 當盒子位置,大小,和其他屬性,比如顏色、字體大小等確定后,瀏覽器把這些元素全按照各有的特性繪制一遍,于是出現了頁面,這個過程稱之為repaint。
二者的關系上,是reflow必然伴隨著repaint,而repaint未必有reflow的參與。
- 比如滾動屏幕,這是reflow 和repaint同時在作用,因為頁面上位置改變了。需要重新布局渲染樹,然后重新繪制。
- 但是如果只修改了顏色,這種不影響布局的屬性,那么就不會用reflow的參與,是需要repaint重新繪制即可。
如何異步加載腳本
-
<script src="script.js"></script>
沒有 defer 或 async,瀏覽器會立即加載并執(zhí)行指定的腳本,“在渲染該 script 標簽之下的文檔元素之前,不會等待后續(xù)要載入的文檔元素,此刻讀到script標簽就會加載并執(zhí)行。 -
<script async src="script.js"></script>
有 async,加載和渲染后續(xù)文檔元素的過程將和 script.js 的加載與執(zhí)行并行進行(同時進行,并行,也就是異步,雙管齊下)。 -
<script defer src="script.js"></script>
有 defer,加載后續(xù)文檔元素的過程將和 script.js 的加載并行進行(異步),但 script.js 的執(zhí)行要在所有元素解析完成之后,DOMContentLoaded 事件觸發(fā)之前完成。

defer & async
注意到async和defer的異同點了嗎?
- 它們都會在加載腳本的過程中,允許后續(xù)文檔元素的加載和渲染。
- 但是 async,是加載到腳本的時候,就會立即執(zhí)行,盡管此時,后續(xù)文檔正在異步加載。
- 而defer,則保證了腳本執(zhí)行的順序,腳本加載和后續(xù)文檔元素的加載渲染是同時的。但是想要執(zhí)行,則必須等后續(xù)所有文檔元素全部解析完成之后。