JS相關(guān)概念總結(jié)

簡單介紹JavaScript的發(fā)展歷史

JavaScript因互聯(lián)網(wǎng)而生,回顧它的歷史要從瀏覽器的歷史講起。

  • 1990年底,歐洲核能研究組織科學(xué)家Tim Berners-Lee發(fā)明了萬維網(wǎng)(World Wide Web),但只能在操作系統(tǒng)的終端里瀏覽和操作,非常不方便。
  • 1992年底,美國國家超級電腦應(yīng)用中心開發(fā)了人類歷史上第一個(gè)瀏覽器Mosaic,從此網(wǎng)頁可以在圖形界面的窗口瀏覽。
  • 1994年10月,NCSA的主要程序員Marc Andreessen聯(lián)合風(fēng)險(xiǎn)投資家Jim Clark,成立了Mosaic通信公司,后改名為Netscape。這家公司的方向,就是在Mosaic的基礎(chǔ)上,開發(fā)面向普通用戶的新一代的瀏覽器Netscape Navigator。
  • 1994年12月,Navigator發(fā)布了1.0版,該公司很快發(fā)現(xiàn)瀏覽器需要一種可嵌入網(wǎng)頁的腳本語言來控制瀏覽器行為。
    管理層對這種瀏覽器腳本語言的設(shè)想是:功能夠用,語法簡單,容易學(xué)習(xí)。當(dāng)時(shí)就職于Netscape的Brendan Eich著手計(jì)劃于1995年2月發(fā)布的Netscape Navigator2開發(fā)LiveScript腳本語言,那年正逢Sun公司的Java語言問世,市場推廣活動非常成功,為趕在發(fā)布日期前完成LiveScript開發(fā),Netscape公司與Sun公司建立了開發(fā)聯(lián)盟。
  • 1995年5月,Brendan Eich只用了10天,就設(shè)計(jì)完成了LiveScript第一版,所以這門語言比較隨意。
  • 1995年12月,Netscape公司與Sun公司達(dá)成協(xié)議,后者允許將這種語言叫做JavaScript,于是Netscape在二代瀏覽器問世前順利蹭到了java的熱度,場面一度十分火爆。
  • 1996年3月,Navigator 2.0瀏覽器正式內(nèi)置了JavaScript腳本語言。
  • 1996年8月,微軟模仿JavaScript開發(fā)了一種相近的語言,取名為JScript。
  • 1996年11月,Netscape公司決定將JavaScript提交給國際標(biāo)準(zhǔn)化組織ECMA,希望JavaScript能夠成為國際標(biāo)準(zhǔn),以此抵抗微軟。
  • 1997年7月,ECMA組織發(fā)布262號標(biāo)準(zhǔn)文件(ECMA-262)的第一版,規(guī)定了瀏覽器腳本語言的標(biāo)準(zhǔn),并將這種語言稱為ECMAScript。這個(gè)版本就是ECMAScript 1.0版。ECMAScript和JavaScript的關(guān)系是,前者是后者的規(guī)格,后者是前者的一種實(shí)現(xiàn)。日常場合這兩個(gè)詞是可以互換的。
  • 1998年6月,ECMAScript 2.0版發(fā)布。
  • 1999年12月,ECMAScript 3.0版發(fā)布,成為JavaScript的通行標(biāo)準(zhǔn),得到了廣泛支持。
  • 2007年10月,ECMAScript 4.0版草案發(fā)布,對3.0版做了大幅升級,預(yù)計(jì)次年8月發(fā)布正式版本。
  • 2008年7月,由于對于下一個(gè)版本應(yīng)該包括哪些功能,各方分歧太大,爭論過于激進(jìn),ECMA開會決定,中止ECMAScript 4.0的開發(fā)(即廢除了這個(gè)版本),將其中涉及現(xiàn)有功能改善的一小部分,發(fā)布為ECMAScript 3.1,而將其他激進(jìn)的設(shè)想擴(kuò)大范圍,放入以后的版本,由于會議的氣氛,該版本的項(xiàng)目代號起名為Harmony(和諧)。會后不久,ECMAScript 3.1就改名為ECMAScript 5。
  • 2009年12月,ECMAScript 5.0版正式發(fā)布。
  • 2011年6月,ECMAscript 5.1版發(fā)布,并且成為ISO國際標(biāo)準(zhǔn)(ISO/IEC 16262:2011)。到了2012年底,所有主要瀏覽器都支持ECMAScript 5.1版的全部功能。
  • 2013年3月,ECMAScript 6草案凍結(jié),不再添加新功能。
  • 2013年12月,ECMAScript 6草案發(fā)布。
  • 2015年6月,ECMAScript 6正式發(fā)布,并且更名為“ECMAScript 2015”。
  • 2016年6月,《ECMAScript 2016標(biāo)準(zhǔn)》發(fā)布。

簡述網(wǎng)頁的渲染機(jī)制

  1. 解析HTML標(biāo)簽,構(gòu)建DOM樹
  2. 解析CSS標(biāo)簽,構(gòu)建CSSOM樹
  3. 把DOM和CSSOM組合成渲染樹
  4. 在渲染樹的基礎(chǔ)上布局,計(jì)算每個(gè)節(jié)點(diǎn)的幾何結(jié)構(gòu)
  5. 把每個(gè)節(jié)點(diǎn)繪制到屏幕上

CSS和JS在網(wǎng)頁中的放置順序是怎樣的?

  1. css放入head中,link引入樣式表和寫在head內(nèi)的style標(biāo)簽里都可以,也可以直接在元素中寫入樣式,但注意要放在js腳本之前。

  2. js放置位置:

  • 放入body底部,</body>之前。
  • 放入head中同時(shí)使用defer或async來延遲或異步加載js。
  • 使用creatElement動態(tài)生成但要注意加載順序。
  • 用ajax加載。

原因:當(dāng)文檔加載過程中遇到JS文件,HTML文檔會掛起渲染過程,不僅要等到文檔中JS文件加載完畢還要等待解析執(zhí)行完畢,才會繼續(xù)HTML的渲染。原因是因?yàn)镴S有可能修改DOM結(jié)構(gòu),這就意味著JS執(zhí)行完成前,后續(xù)所有資源的下載是沒有必要的,這就是JS阻塞后續(xù)資源下載的根本原因,即無論當(dāng)前JS代碼是內(nèi)嵌還是在外部文件中,頁面的下載和渲染都必須停下來等待腳本執(zhí)行完成,JS執(zhí)行過程越久,瀏覽器等待響應(yīng)用戶輸入的時(shí)間就越長,所以盡量把JS放在底部、設(shè)置script標(biāo)簽的defer或async屬性、合并腳本等方法可起到性能優(yōu)化效果。

解釋白屏和FOUC

  1. 白屏:
  • 對IE來說,把樣式放在底部時(shí),在某些場景下(如打開新窗口/刷新頁面等)頁面會出現(xiàn)白屏,而不是內(nèi)容逐步展現(xiàn)。
  • 如果使用@import標(biāo)簽,即使將CSS寫入外部樣式表由link引入并放在頭部,也可能出現(xiàn)白屏。
  • 把js文件放入頁面頂部而未使用defer或async延遲或異步加載js文件,從而阻塞html與css的加載也會導(dǎo)致白屏。
  • 另外:Chrome會同時(shí)加載html和css分別構(gòu)建DOM樹和CSSOM樹,等到二者都構(gòu)建完成后再繪制渲染樹,然后顯示出頁面,當(dāng)外部css樣式表設(shè)置了延時(shí)或者加載的時(shí)間比較久時(shí)就會顯示出白屏,與瀏覽器的渲染機(jī)制有關(guān)。
  1. FOUC:
    Flash of unsettled content:無樣式內(nèi)容閃爍。對IE來說,把樣式放在底部時(shí),在某些場景下(如點(diǎn)擊鏈接、輸入U(xiǎn)RL、使用書簽進(jìn)入等)頁面會出現(xiàn)FOUC現(xiàn)象,具體表現(xiàn)為逐步加載無樣式的內(nèi)容,等CSS加載完成后頁面突然展現(xiàn)樣式;對Firefox來說會先顯示已加載的html內(nèi)容,再逐步加載無樣式內(nèi)容,等css全部加載完成后頁面突然展現(xiàn)樣式,所以Firefox會一直表現(xiàn)出FOUC。

async和defer的作用是什么?有什么區(qū)別

async和defer用于異步或延遲加載腳本。
沒有 defer 或 async,瀏覽器會立即加載并執(zhí)行指定的腳本,“立即”指的是讀到就加載并執(zhí)行。也就是說腳本會阻塞其后內(nèi)容的解析和執(zhí)行。

  1. 作用:
  • async(異步):定義了async屬性的腳本相對于頁面的其他部分異步執(zhí)行(同時(shí)執(zhí)行),作用是不讓頁面等待兩個(gè)或以上的腳本下載和執(zhí)行,從而異步加載頁面的其他內(nèi)容。
<!DOCTYPE html>
<head>
    <title>Example HTML Page</title>
    <script type="text/javascript" async src="example1.js"></script> 
    <script type="text/javascript" async src="example2.js"></script>
</head>
<body>
    <!-- 這里放內(nèi)容 --> 
</body>
</html>

以上代碼中evample2.js可能會在example1.js之前執(zhí)行,所以確保二者之間互不依賴很重要。

  • defer(延遲):定義了defer屬性的腳本會被延遲到整個(gè)頁面都解析完畢后再執(zhí)行。
<!DOCTYPE html>
<head>
    <title>Example HTML Page</title>
    <script type="text/javascript" defer src="example1.js"></script>
    <script type="text/javascript" defer src="example2.js"></script>
</head>
<body>
    <!-- 這里放內(nèi)容 -->
</body>
</html>

以上代碼中雖然我們把<script>放在了<head>中,但其中包含的腳本文件將延遲到瀏覽器遇到</html>后再執(zhí)行。HTML5規(guī)范要求腳本按照它們出現(xiàn)的先后順序執(zhí)行,即第一個(gè)延遲腳本先于第二個(gè)延遲腳本執(zhí)行,而這兩個(gè)腳本會先于DOMContentLoaded事件執(zhí)行,但現(xiàn)實(shí)中延遲腳本并不一定會按照順序執(zhí)行,也不一定會在DOMContentLoaded事件觸發(fā)前執(zhí)行,所以一個(gè)文檔里最好只包含一個(gè)延遲腳本。

async-VS-defer-圖片來自文章最底部參考資料

上圖的意思是:瀏覽器在解析HTML文件時(shí),遇上沒有設(shè)置defer或async屬性的腳本,瀏覽器讀到該腳本就加載并執(zhí)行,腳本會阻塞其后內(nèi)容的執(zhí)行;
遇上設(shè)有async屬性的腳本,會在HTML解析過程中下載該腳本,并在完成下載后暫停HTML的解析來執(zhí)行這個(gè)異步腳本,直到執(zhí)行完成后再繼續(xù)HTML的解析;
遇上設(shè)有defer屬性的腳本,會在HTML解析過程中下載該腳本,在HTML解析完成后才執(zhí)行該文件。延遲腳本按照它們在文檔中出現(xiàn)的順序執(zhí)行。

  1. 共同點(diǎn):
  • 設(shè)置了async或defer屬性的腳本不會阻塞頁面渲染
  • async和defer屬性決定了js腳本的執(zhí)行方式,內(nèi)聯(lián)腳本會忽略這兩個(gè)屬性
  • 使用這兩個(gè)屬性的腳本中不能調(diào)用document.write
  • 所有defer和async腳本執(zhí)行完畢后,DOMContentLoaded和load事件都將觸發(fā)
  1. 區(qū)別:
  • 異步腳本一定會在頁面的load事件前執(zhí)行,但可能在DOMContentLoaded事件觸發(fā)之前或之后執(zhí)行,所以可能出現(xiàn)無順序加載js的情況;延遲腳本在文檔完成解析后,執(zhí)行理論上是有序的但現(xiàn)實(shí)中并不能保證順序,也不一定會在DOMContentLoaded事件觸發(fā)前執(zhí)行。
    (實(shí)際實(shí)驗(yàn)得到的結(jié)果是,在頁面中有2個(gè)defer腳本,2個(gè)async腳本的情況下,這四個(gè)腳本的執(zhí)行順序是無序的,但單看defer或單看async,他們都是有序的,且這四個(gè)腳本文件都會在DOMContentLoaded事情之前執(zhí)行完畢,load事件永遠(yuǎn)最后觸發(fā)。)
  1. 關(guān)聯(lián):
  • async為true,腳本將在加載完成后立即執(zhí)行
  • async為false,defer為true,腳本將在頁面全部解析完成后執(zhí)行
  • async和defer都為false,腳本將阻塞頁面解析,即頁面解析被掛起轉(zhuǎn)而下載并立即執(zhí)行腳本文件
  1. 注意事項(xiàng):
    如果一個(gè)外部腳本依賴于另一外部腳本,請將它們標(biāo)記為defer,并按它們被聲明的順序執(zhí)行。
    瀏覽器發(fā)起資源請求request的時(shí)間都比較接近,除非DOM樹非常長,時(shí)間可能會有明顯差別。但資源響應(yīng)時(shí)間responsive的時(shí)間差別較大,瀏覽器會根據(jù)情況作出優(yōu)化,圖片字體等優(yōu)先級較低,一般等到最后才加載完成(比js還久)。

repaint 和 reflow

  • 什么是repaint和reflow:
    瀏覽器根據(jù)自己默認(rèn)的或開發(fā)人員給出的樣式表來計(jì)算DOM結(jié)構(gòu)中的各個(gè)盒模型該出現(xiàn)的位置就是reflow;當(dāng)各種盒子的位置、大小及其他屬性,例如顏色、字體大小等都確定下來后,瀏覽器開始布局渲染樹并將其繪制到屏幕上,這個(gè)過程就是repaint。

瀏覽器解析和渲染頁面過程中會涉及到reflow(回流)和repaint(重繪),就某些瀏覽器如Opera而言,大部分的reflow將導(dǎo)致頁面重新渲染,其變化涉及到部分甚至是整個(gè)頁面的布局,而repaint則導(dǎo)致瀏覽器必須驗(yàn)證DOM樹上其他節(jié)點(diǎn)元素的可見性。reflow和repaint過程非常消耗性能,尤其在移動設(shè)備上,會破壞用戶體驗(yàn),造成頁面卡頓,所以應(yīng)盡可能減少reflow和repaint。

  • 導(dǎo)致回流的原因:

    • 調(diào)整窗口大小
    • 改變字體
    • 增加或移除樣式表
    • 內(nèi)容變化,如在input框中輸入文字
    • 激活CSS偽類,如hover
    • 操作class屬性
    • 腳本操作DOM
    • 計(jì)算offsetWidth和offsetHeight屬性
    • 設(shè)置style屬性的值
  • 如何避免回流或?qū)⑺鼈儗π阅艿挠绊懡档阶畹停?/p>

    • 盡可能在DOM樹最末端通過改變元素的class名的方式設(shè)定元素的樣式:回流會順行或逆行傳遞給周圍的節(jié)點(diǎn),在DOM樹里改變class限制了回流的范圍,使其影響盡可能少的節(jié)點(diǎn)。
    • 避免設(shè)置多項(xiàng)內(nèi)聯(lián)樣式:因?yàn)槊總€(gè)內(nèi)聯(lián)樣式都會造成回流,樣式應(yīng)合并在一個(gè)外部類,這樣當(dāng)該元素的class屬性被操控時(shí)只會產(chǎn)生一個(gè)回流。
    • 應(yīng)用元素的動畫使用position屬性的absolute或fixed值:這樣設(shè)置不影響其他元素的布局,只會導(dǎo)致重繪而不是完整回流。
    • 犧牲平滑度換取速度:你可能想每次1px移動一個(gè)動畫,但是此動畫及隨后的回流使用了100%的CPU,動畫看上去就會是跳動的,因?yàn)闉g覽器正在與更新回流做斗爭。而動畫元素每次移動3px,在非常快的機(jī)器上看起來平滑度低了,但它不會導(dǎo)致CPU在較慢的機(jī)器和移動設(shè)備中抖動。
    • 避免使用table布局:table是個(gè)和罕見的可以影響在它們之前已經(jīng)進(jìn)入的DOM元素的顯示的元素。想象一下,因?yàn)楸砀褡詈笠粋€(gè)單元格的內(nèi)容過寬而導(dǎo)致縱列大小完全改變。這就是為什么所有的瀏覽器都逐步地不支持table表格的渲染。另外一個(gè)原因說明表格布局很糟糕,根據(jù)Mozilla,一些小的變化將導(dǎo)致表格(table)中的所有其他節(jié)點(diǎn)回流。
    • 避免使用CSS的JS表達(dá)式:因?yàn)樗麄兠看味贾匦掠?jì)算全部或部分文檔而導(dǎo)致每秒產(chǎn)生成千上萬次回流。
    • 設(shè)置box-sizing: border-box;把標(biāo)準(zhǔn)盒模型轉(zhuǎn)換為IE盒模型,告訴瀏覽器去理解你設(shè)置的邊框和內(nèi)邊距的值是包含在width內(nèi)的。設(shè)置后,即使padding或者border發(fā)生了改變,盒子寬高不會發(fā)生變化,只會重繪,不會回流。

關(guān)于瀏覽器渲染更詳細(xì)內(nèi)容可參考我的博客第六節(jié)


參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. CSS和JS在網(wǎng)頁中的放置順序是怎樣的?CSS必須是在html之前載入,所以放在head標(biāo)簽里。JS放在CS...
    好好頑閱讀 81評論 0 0
  • 1. CSS和JS在網(wǎng)頁中的放置順序是怎樣的? css放在head標(biāo)簽內(nèi),防止渲染時(shí)出現(xiàn)白屏 js放在最后body...
    billa_8f6b閱讀 587評論 0 0
  • 前端開發(fā)面試知識點(diǎn)大綱: HTML&CSS: 對Web標(biāo)準(zhǔn)的理解、瀏覽器內(nèi)核差異、兼容性、hack、CSS基本功:...
    秀才JaneBook閱讀 2,499評論 0 25
  • JavaScript的發(fā)展歷史 JavaScript因?yàn)g覽器而生,回顧它的歷史要從瀏覽器的歷史講起。 1990年底...
    左冬的博客閱讀 345評論 0 5
  • 網(wǎng)頁 什么是網(wǎng)頁? 網(wǎng)頁 =Html+CSS+JavaScriptHtml是網(wǎng)頁的內(nèi)容CSS是網(wǎng)頁的樣式JavaS...
    YM雨蒙閱讀 231評論 0 3