新聞中心
無(wú)論當(dāng)前 JavaScript 代碼是內(nèi)嵌還是在外鏈文件中,頁(yè)面的下載和渲染都必須停下來(lái)等待腳本執(zhí)行完成。JavaScript 執(zhí)行過(guò)程耗時(shí)越久,瀏覽器等待響應(yīng)用戶(hù)輸入的時(shí)間就越長(zhǎng)。瀏覽器在下載和執(zhí)行腳本時(shí)出現(xiàn)阻塞的原因在于,腳本可能會(huì)改變頁(yè)面或 JavaScript 的命名空間,它們對(duì)后面頁(yè)面內(nèi)容造成影響。一個(gè)典型的例子就是在頁(yè)面中使用document.write()。例如清單 1
清單 1 JavaScript 代碼內(nèi)嵌示例

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


咨詢(xún)
建站咨詢(xún)