現代瀏覽器中的3f1c4e4b6b16bbbd69b2ee476dc4f83a標籤分成了兩種新類型:經典型和非阻塞型。接下來討論如何運用這兩種標籤來盡快載入頁面。 1、阻塞型腳本何去何從? 標準版本的3f1c4e4b6b16bbbd69b2ee476dc4f83a標籤常被稱為阻塞型標籤。這個字必須放在上下文中理解:現代瀏覽器看到阻塞型3f1c4e4b6b16bbbd69b2ee476dc4f83a標籤時,會跳過阻塞點繼續讀取文件及下載其他資源(腳本和樣式表)。但直到腳本下載完畢並執行之後,瀏覽器才會評估阻塞點之後的那些資源。因此,如果網頁文件的93f0f5c25f18dab9d176bd4f6de5d30e標籤裡有5 個阻塞型3f1c4e4b6b16bbbd69b2ee476dc4f83a標籤,則在所有這5 個腳本都下載完畢並運行之前,用戶除了頁面標題之外看不到任何東西。不僅如此,即便這些腳本運行了,它們也只能看到阻塞點之前的那部分文件。如果想看到6c04bd5ca3fcae76e30b72ad730ca86d標籤中正等待載入的那些好東西,就必須給像document.onreadystatechange 這樣的事件綁定一個事件處理器。 基於上述原因,現在越來越流行把腳本放在頁面6c04bd5ca3fcae76e30b72ad730ca86d標籤的尾部。這樣,一方面使用者可以更快地看到頁面,另一方面腳本也可以主動親密接觸DOM 而無需等待事件來觸發自己。對大多數腳本而言,這次「搬家」是個巨大的進步。 但並非所有腳本都一樣。在向下搬動腳本之前,請先問自己2 個問題。 該腳本是否有可能被6c04bd5ca3fcae76e30b72ad730ca86d標籤裡的內嵌JavaScript 直接呼叫?答案可能一目了然,但仍值得核實一遍。 該腳本是否會影響已渲染頁面的外觀? Typekit 宿主字體就是一個例子。如果把Typekit 腳本放在文件結尾,那麼頁面文字就會渲染兩次,也就是讀取文件時即時渲染,腳本執行時再渲染。 上述問題只要有一個答案是肯定的,那麼該腳本就應該放在93f0f5c25f18dab9d176bd4f6de5d30e標籤中,否則就可以放在6c04bd5ca3fcae76e30b72ad730ca86d標籤中,文檔形如: </head> <body> <!-- content goes here --> <script src="bodyScripts.js"> 這確實大大縮短了載入時間,但要注意一點,這可能會讓使用者有機會在載入bodyScripts.js 之前與頁面互動。 2、腳本的提前載入與延遲執行 上面建議將大多數腳本放在6c04bd5ca3fcae76e30b72ad730ca86d中,因為這樣既能讓使用者更快看到網頁,又能避免操控DOM之前綁定「就緒」事件的開銷。但這種方式也有一個缺點,就是瀏覽器在載入完整個文件之前無法載入這些腳本,這對那些透過慢速連線傳送的大型文件來說會是一大瓶頸。 理想情況下,腳本的載入應該與文件的載入同時進行,並且不影響DOM 的渲染。這樣,一旦文件就緒就可以運行腳本,因為已經按照3f1c4e4b6b16bbbd69b2ee476dc4f83a標籤的順序載入了對應腳本。 如果大家已經讀到這裡了,那麼一定會迫不及待地想寫一個自訂Ajax 腳本載入器以滿足這樣的需求!不過,大多數瀏覽器都支援一個更為簡單的解決方案。 新增defer(延遲)屬性相當於對瀏覽器說:「請馬上開始載入這個腳本吧,但是,請等到文件就緒且所有先前具有defer 屬性的腳本都結束運行之後再運行它。 不足之處就是,並非所有瀏覽器都支援defer屬性。這意味著,如果您想確保自己的延遲腳本能在文件載入後運行,就必須將所有延遲腳本的程式碼都封裝在諸如jQuery 之$(document).ready 之類的結構中。 上一節的頁面範例改進如下: <script defer src="deferredScripts.js"> 請記住deferredScripts 的封裝很重要,這樣即使瀏覽器不支援defer,deferredScripts 也會在文件就緒事件之後才執行。如果頁面主體內容遠遠超過幾千字節,那麼付出這點代價是完全值得的。 3、 腳本的並行加載 如果你是斤斤計較到毫秒級頁面加載時間的完美主義者,那麼defer也許就像是淡而無味的薄鹽醬油。你可不想一直等到先前所有的defer 腳本都運行結束,當然也肯定不想等到文檔就緒之後才運行這些腳本,你就是想盡快加載並且盡快運行這些腳本。這也正是現代瀏覽器提供了async(非同步)屬性的原因。 <script async src = "roadRunner.js"></pre><p>如果说defer 让我们想到一种静静等待文档加载的有序排队场景,那么async 就会让我们想到混乱的无政府状态。前面给出的那两个脚本会以任意次序运行,而且只要JavaScript 引擎可用就会立即运行,而不论文档就绪与否。<br>对大多数脚本来说,async 是一块难以下咽的鸡肋。async 不像defer那样得到广泛的支持。同时,由于异步脚本会在任意时刻运行,它实在太容易引起海森堡蚁虫之灾了(脚本刚好结束加载时就会蚁虫四起)。<br>当我们加载一些第三方脚本,而且也不在乎它们谁先运行谁后运行。因此,对这些第三方脚本使用async 属性,相当于一分钱没花就提升了它们的运行速度。<br>上一个页面示例再添加两个独立的第三方小部件,得到的结果如下:</p><pre class="brush:js;toolbar:false"><html> <head> <!-- metadata and stylesheets go here --> <script src="headScripts.js"> <script src="deferredScripts.js" defer>