2012-01-20 107 views
15

我注意到我的網站(工作)的<head>,有很多<link rel="stylesheet" type="text/css" href="" /><script type="text/javascript" src="">標籤。還有更多隻爲特定頁面加載的JavaScript/CSS文件(我們使用的是CodeIgniter,文件路徑被傳遞給標題視圖)。我正在考慮使用條件/異步裝載器(例如。yepnope.js,head.js等),但我注意到這樣做的一個小問題。延遲加載JavaScript和內嵌JavaScript

在我們的觀點中,有內嵌JavaScript,有些使用$(function(){})某些用途$(document).ready(function(){}),有些使用的代碼(使用jQuery)不在ready塊中。

沒有編輯EVERY視圖文件來將其代碼包裝在一個函數中,並調用當加載JS文件時,有沒有一種方法可以延遲內聯代碼,直到JavaScript被異步加載?

+3

號,但你可以通過使用'窗口讓你的工作更容易$ = waitUntilCodeLoaded'。這樣你只能改變一半的內聯代碼。事實上,內聯代碼很糟糕,所有內部代碼都是外部的 – Raynos

+0

@Raynos:我正在考慮將所有的代碼移到他們自己的文件中,但是我們有很多意見,這需要一段時間。我希望能有一個快捷的,可靠的解決方法。 –

+0

Raynos是對的 – Salaros

回答

28

實際上,你可以lazyload聯JavaScript:文/ delayscript

FROM

<!– Inline Script –> 
<script type="text/javascript" language="javaScript"> 
      /* Code */ 
</script> 

<!– Inline Script –> 
<script type="text/delayscript"> 
      /* Code */ 
</script> 

給腳本: 1-變化內嵌腳本類型參數標記一個自定義MIME類型text/delayscript強制瀏覽器忽略它的內容(請注意,完全忽略它將默認爲text/javascript )。

2-懶惰加載所有內聯腳本 一旦頭。JS(或者你可能使用的其他框架)證實,懶加載所有的外部JS,你就可以抓住所有的自定義腳本標記的內容,並在頁面注入其中:

<script> 
head.ready(function() { 
    var 
     _head = document.getElementsByTagName("head")[0], 
     _script = document.createElement('script'), 
     _scripts = document.getElementsByTagName("script"), 
     _txt = "text/delayscript", 
     _contents = [] 
    ; 

    for(var i=0,l=_scripts.length;i<l;i++){ 
     var _type = _scripts[i].getAttribute("type"); 
      if(_type && _type.toLowerCase() ==_txt) 
       _contents.push(_scripts[i].innerHTML) 
    } 


    _script.type = 'text/javascript'; 
    _script.innerHTML = _contents.join(" "); 
    _head.appendChild(_script); 

}); 

爲了更加優雅,您可以實際上將內聯腳本保留在DOM樹中的原始層次結構中,而不是像上面所建議的那樣將其所有內容都塞進一個腳本中,方法是將標記的內聯腳本標記替換爲新的腳本標記has mime type text/javascript:

head.ready(function() { 
var 
    _scripts = document.getElementsByTagName("script"), 
    _doc = document, 
    _txt = "text/delayscript" 
; 

for(var i=0,l=_scripts.length;i<l;i++){ 
    var _type = _scripts[i].getAttribute("type"); 
     if(_type && _type.toLowerCase() ==_txt) 
      _scripts[i].parentNode.replaceChild((function(sB){ 
       var _s = _doc.createElement('script'); 
       _s.type = 'text/javascript'; 
       _s.innerHTML = sB.innerHTML; 

       return _s; 
      })(_scripts[i]), _scripts[i]); 
} 
}); 
+0

嘿,這很聰明。因此,請告訴瀏覽器忽略腳本標記,然後在加載外部腳本時將它們加載回頁面。我喜歡。 –

+0

只要您的內聯腳本中沒有document.write,就會工作。因此,除了上面提到的這種方法之外,使用諸如yepnope.js(我強烈建議),head.js或require.js之類的東西,可以實時延遲加載任何舊版JavaScript,因此獲得了巨大的感知加載時間。 – YoussefTaghlabi

+0

我沒有使用'document.write',所以這很好。問題是,我想懶加載外部,但內聯代碼依賴於它。用這種方法,我可以在正確的時間運行腳本。 :-) –

5

你必須考慮將內嵌代碼「外」,並附

<script defer="defer" type="text/javascript" src=""> 
+1

究竟是什麼'推遲=「推遲」'做? –

+0

@Rocket:http://www.w3.org/TR/html4/interact/scripts.html#adef-defer –

+0

@Rocket:只是提供參考,你必須要求澄清:) –

2

首先,我會建議你不但非常認真,並沒有分析在客戶端腳本的負載爲第一次JavaScript加載,但第二次加載相同的JavaScript文件或加載到另一頁時。如果Web服務器在腳本上正確設置了ETag,或者如果對JavaScript文件使用HTTP的其他緩存選項(請參閱caching tutorial以獲取詳細信息),則不會發生加載文件本身,只有緩存重新驗證將會完成。所以可能是因爲你描述的問題並不像它看起來那麼重要。

如果您決定動態加載一些腳本,則可以使用jQuery.getScript並將所有相關代碼放在success回調中。如果您需要加載一個或兩個JavaScript文件,這種方式將非常有效,但如果您需要加載具有更復雜依賴性的JavaScript文件列表,則實現可能並不那麼容易。在這種情況下,您可以使用<head>中的document.writeln<head>中的方法的使用幾乎沒有缺點(詳情請參閱here)。

+0

我知道如何動態加載JavaScript。我的問題是,我正在動態加載在身體某處使用的庫。所以內聯腳本失敗,因爲庫不在那裏。我想知道是否有一種快速的方法來解決這個問題,而不需要將所有的JavaScript複製到他們自己的文件中。 –

+0

@Rocket:爲什麼你不能在加載庫的'.getScript'調用的'success'句柄中放置使用庫的代碼(內聯腳本)? – Oleg

+0

我可以,但有很多內聯腳本標記。這將需要很長時間。我想知道如果我能以某種方式讓瀏覽器自動爲我做。 –

0

看看使用headjs。這是一個不錯的輕量級庫,將爲您完成這一切。

+0

我看過headjs,但問題是所有的內嵌JavaScript。我想找出一種方法來延遲執行體內的腳本標記,直到加載庫。 –

+0

你可以將腳本標記的內容包裝在註釋中,然後正則表達式匹配註釋中的代碼,然後在全局範圍內對其進行評估:) – skarE

+0

但是如果它們是註釋,我該如何讀取它們? –

1

根據您的設置,您可能需要查看www.cloudflare.com的服務。他們目前的測試功能稱爲火箭加載器,就是這樣,包括內聯腳本。

這是一項免費服務。試試吧;)

另外,你在上面自由緩存代理:)

+0

我實際使用的CloudFlare爲我的個人網站: - ) –

+0

@火箭你的使用案例允許你試試嗎?因爲他們在服務器端使用代理處理腳本,所以它對開發人員來說是透明的。包括內聯腳本。火箭裝載機雖然有它的怪癖。例如,當火箭加載器打開時,CMS混凝土5的(內聯)編輯模式被破壞。 –

+0

這是爲了工作。我可以向我的老闆提及,因爲我無法控制服務器/ DNS。 –

0

而是內嵌腳本,創建內聯函數。然後在JavaScript文件的末尾,調用該函數(如果存在)。

function inline_script() {.. code ..} 

內,您的串連的jQuery +等異步JavaScript文件:

if (typeof(inline_script) == 'function') inline_script() 

你必須做一些洗牌,以確保您只有一個每頁inline_script,或者使用某種緩存來把它們放在一起,如果你多次調用它。

它仍然是在當前時代一個有趣的問題,儘管這個問題是舊的,異步腳本=相當真棒

1

HTML5引入了具有確定src腳本新async參數。

您可以直接將它添加任何<script>元素:

<script src='/js/script.js' async></script> 

但是:請記住,它不會在內嵌腳本工作!

如果你的某些網頁的混合是外部和內嵌腳本,如果你加載外部異步,這意味着內嵌腳本實際上異步的...它可以有不良影響之前執行

設置此布爾屬性以指示瀏覽器應該在可能的情況下異步執行腳本。它對內聯腳本(即沒有src屬性的腳本)沒有影響。

例如,如果您有以下配置:

<script src='/js/jquery.min.js' async></script> 
<script> 
    // --> jQuery won't be loaded when this script will be executed! 
    // This will throw an error. 
    $(function() { 
     $('#element').doSomething(); 
    }); 
</script>