這篇文章主要講解了“JavaScript的性能優(yōu)化方法有哪些”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript的性能優(yōu)化方法有哪些”吧!
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供赫山網(wǎng)站建設、赫山做網(wǎng)站、赫山網(wǎng)站設計、赫山網(wǎng)站制作等企業(yè)網(wǎng)站建設、網(wǎng)頁設計與制作、赫山企業(yè)網(wǎng)站模板建站服務,十余年赫山做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡服務。
無論當前 JavaScript 代碼是內(nèi)嵌還是在外鏈文件中,頁面的下載和渲染都必須停下來等待腳本執(zhí)行完成。JavaScript 執(zhí)行過程耗時越久,瀏覽器等待響應用戶輸入的時間就越長。瀏覽器在下載和執(zhí)行腳本時出現(xiàn)阻塞的原因在于,腳本可能會改變頁面或 JavaScript 的命名空間,它們對后面頁面內(nèi)容造成影響。一個典型的例子就是在頁面中使用document.write()
。
清單 1 JavaScript 代碼內(nèi)嵌示例
Source Example
當瀏覽器遇到標簽時,當前
HTML 頁面無從獲知
JavaScript 是否會向
標簽添加內(nèi)容,或引入其他元素,或甚至移除該標簽。因此,這時瀏覽器會停止處理頁面,先執(zhí)行
JavaScript代碼,然后再繼續(xù)解析和渲染頁面。同樣的情況也發(fā)生在使用
src
屬性加載
JavaScript的過程中,瀏覽器必須先花時間下載外鏈文件中的代碼,然后解析并執(zhí)行它。在這個過程中,頁面渲染和用戶交互完全被阻塞了。
腳本位置
HTML 4 規(guī)范指出 標簽可以放在 HTML 文檔的
或
中,并允許出現(xiàn)多次。Web 開發(fā)人員一般習慣在
中加載外鏈的 JavaScript,接著用
標簽用來加載外鏈的 CSS 文件或者其他頁面信息。例如清單 2
清單 2 低效率腳本位置示例
Source Example Hello world!
然而這種常規(guī)的做法卻隱藏著嚴重的性能問題。在清單 2 的示例中,當瀏覽器解析到 標簽(第 4 行)時,瀏覽器會停止解析其后的內(nèi)容,而優(yōu)先下載腳本文件,并執(zhí)行其中的代碼,這意味著,其后的 styles.css 樣式文件和
標簽都無法被加載,由于
標簽無法被加載,那么頁面自然就無法渲染了。因此在該 JavaScript 代碼完全執(zhí)行完之前,頁面都是一片空白。圖 1 描述了頁面加載過程中腳本和樣式文件的下載過程。
圖 1 JavaScript 文件的加載和執(zhí)行阻塞其他文件的下載
我們可以發(fā)現(xiàn)一個有趣的現(xiàn)象:第一個 JavaScript 文件開始下載,與此同時阻塞了頁面其他文件的下載。此外,從 script1.js 下載完成到 script2.js 開始下載前存在一個延時,這段時間正好是 script1.js 文件的執(zhí)行過程。每個文件必須等到前一個文件下載并執(zhí)行完成才會開始下載。在這些文件逐個下載過程中,用戶看到的是一片空白的頁面。
從 IE 8、Firefox 3.5、Safari 4 和 Chrome 2 開始都允許并行下載 JavaScript 文件。這是個好消息,因為標簽在下載外部資源時不會阻塞其他
標簽。遺憾的是,JavaScript 下載過程仍然會阻塞其他資源的下載,比如樣式文件和圖片。盡管腳本的下載過程不會互相影響,但頁面仍然必須等待所有 JavaScript 代碼下載并執(zhí)行完成才能繼續(xù)。因此,盡管最新的瀏覽器通過允許并行下載提高了性能,但問題尚未完全解決,腳本阻塞仍然是一個問題。
由于腳本會阻塞頁面其他資源的下載,因此推薦將所有標簽盡可能放到
標簽的底部,以盡量減少對整個頁面下載的影響。例如清單 3
清單 3 推薦的代碼放置位置示例
Source Example Hello world!
這段代碼展示了在 HTML 文檔中放置標簽的推薦位置。盡管腳本下載會阻塞另一個腳本,但是頁面的大部分內(nèi)容都已經(jīng)下載完成并顯示給了用戶,因此頁面下載不會顯得太慢。這是優(yōu)化 JavaScript 的首要規(guī)則:將腳本放在底部。
組織腳本
由于每個標簽初始下載時都會阻塞頁面渲染,所以減少頁面包含的
標簽數(shù)量有助于改善這一情況。這不僅針對外鏈腳本,內(nèi)嵌腳本的數(shù)量同樣也要限制。瀏覽器在解析 HTML 頁面的過程中每遇到一個
標簽,都會因執(zhí)行腳本而導致一定的延時,因此最小化延遲時間將會明顯改善頁面的總體性能。
這個問題在處理外鏈 JavaScript 文件時略有不同??紤]到 HTTP 請求會帶來額外的性能開銷,因此下載單個 100Kb 的文件將比下載 5 個 20Kb 的文件更快。也就是說,減少頁面中外鏈腳本的數(shù)量將會改善性能。
通常一個大型網(wǎng)站或應用需要依賴數(shù)個 JavaScript 文件。您可以把多個文件合并成一個,這樣只需要引用一個標簽,就可以減少性能消耗。文件合并的工作可通過離線的打包工具或者一些實時的在線服務來實現(xiàn)。
需要特別提醒的是,把一段內(nèi)嵌腳本放在引用外鏈樣式表的之后會導致頁面阻塞去等待樣式表的下載。這樣做是為了確保內(nèi)嵌腳本在執(zhí)行時能獲得最精確的樣式信息。因此,建議不要把內(nèi)嵌腳本緊跟在
標簽后面。
無阻塞的腳本
減少 JavaScript 文件大小并限制 HTTP 請求數(shù)在功能豐富的 Web 應用或大型網(wǎng)站上并不總是可行。Web 應用的功能越豐富,所需要的 JavaScript 代碼就越多,盡管下載單個較大的 JavaScript 文件只產(chǎn)生一次 HTTP 請求,卻會鎖死瀏覽器的一大段時間。為避免這種情況,需要通過一些特定的技術(shù)向頁面中逐步加載 JavaScript 文件,這樣做在某種程度上來說不會阻塞瀏覽器。
無阻塞腳本的秘訣在于,在頁面加載完成后才加載 JavaScript 代碼。這就意味著在 window
對象的 onload
事件觸發(fā)后再下載腳本。有多種方式可以實現(xiàn)這一效果。
延遲加載腳本
HTML 4 為標簽定義了一個擴展屬性:
defer
。Defer
屬性指明本元素所含的腳本不會修改 DOM,因此代碼能安全地延遲執(zhí)行。defer
屬性只被 IE 4 和 Firefox 3.5 更高版本的瀏覽器所支持,所以它不是一個理想的跨瀏覽器解決方案。在其他瀏覽器中,defer
屬性會被直接忽略,因此標簽會以默認的方式處理,也就是說會造成阻塞。然而,如果您的目標瀏覽器支持的話,這仍然是個有用的解決方案。清單 4 是一個例子
清單 4 defer 屬性使用方法示例
帶有 defer
屬性的標簽可以放置在文檔的任何位置。對應的 JavaScript 文件將在頁面解析到
標簽時開始下載,但不會執(zhí)行,直到 DOM 加載完成,即
onload
事件觸發(fā)前才會被執(zhí)行。當一個帶有 defer
屬性的 JavaScript 文件下載時,它不會阻塞瀏覽器的其他進程,因此這類文件可以與其他資源文件一起并行下載。
任何帶有 defer
屬性的元素在 DOM 完成加載之前都不會被執(zhí)行,無論內(nèi)嵌或者是外鏈腳本都是如此。清單 5 的例子展示了
defer
屬性如何影響腳本行為:
清單 5 defer 屬性對腳本行為的影響
Script Defer Example
這段代碼在頁面處理過程中彈出三次對話框。不支持 defer
屬性的瀏覽器的彈出順序是:“defer”、“script”、“l(fā)oad”。而在支持 defer
屬性的瀏覽器上,彈出的順序則是:“script”、“defer”、“l(fā)oad”。請注意,帶有 defer
屬性的元素不是跟在第二個后面執(zhí)行,而是在
onload
事件被觸發(fā)前被調(diào)用。
如果您的目標瀏覽器只包括 Internet Explorer 和 Firefox 3.5,那么 defer
腳本確實有用。如果您需要支持跨領域的多種瀏覽器,那么還有更一致的實現(xiàn)方式。
HTML 5 為標簽定義了一個新的擴展屬性:
async
。它的作用和 defer
一樣,能夠異步地加載和執(zhí)行腳本,不因為加載腳本而阻塞頁面的加載。但是有一點需要注意,在有 async
的情況下,JavaScript 腳本一旦下載好了就會執(zhí)行,所以很有可能不是按照原本的順序來執(zhí)行的。如果 JavaScript 腳本前后有依賴性,使用 async
就很有可能出現(xiàn)錯誤。
動態(tài)腳本元素
文檔對象模型(DOM)允許您使用 JavaScript 動態(tài)創(chuàng)建 HTML 的幾乎全部文檔內(nèi)容。元素與頁面其他元素一樣,可以非常容易地通過標準 DOM 函數(shù)創(chuàng)建:
清單 6 通過標準 DOM 函數(shù)創(chuàng)建