2012-03-07 17 views
1

我想模擬天生此行爲:正在使用document.write唯一可能的方式來同步跨瀏覽器跨域加載腳本?

<script src="console.log.1.js"></script> 
<script>console.log(2)</script> 
<script>console.log(3)</script> 

這登出:

1 
2 
3 

這樣做行不通:

<script> 
var x = document.createElement("script"); 
x.src = "console.log.1.js"; 
x.async = false; 
x.defer = false; 
document.body.appendChild(x); 
console.log("2"); 
console.log("3"); 
</script> 

它登出:

2 
3 
1 

The唯一的辦法,我發現到目前爲止實現它:

<script> 
document.write("<scrip" + "t src='console.log.1.js'></scrip" + "t>"); 
</script> 
<script> 
console.log("2"); 
console.log("3"); 
</script> 

那是真給力外部腳本的同步加載在所有瀏覽器的唯一途徑?爲什麼不設置async = false,推遲= false工作?

UPDATE

僅供參考,如果有人想知道,下面的文件撰寫工作開始(在Chrome ..):

<script> 
    // http://jsbin.com/avatiw logs "during" 
    document.write('<scrip' + 't>console.log("before");document.write("<scrip" + "t src=\\"http://jsbin.com/avatiw\\"></scrip" + "t>");</scrip' + 't>'); 
    document.write('<scrip' + 't>console.log("after");</scrip' + 't>'); 
</script> 

工程和註銷:

"before" 
"during" 
"after" 
+0

你有沒有考慮使用'document.getElementsByTagName( '身體' )[0] .appendChild(X);'?但即使如此,是否有一個原因,你不是追加到'head'而不是'body'? – 2012-03-07 17:46:43

+1

我希望仍然會註銷231,就像第二個例子。 – Karolis 2012-03-07 17:48:44

+0

@DavidThomas:我和Karolis在一起。這並不是說腳本元素不會在執行腳本元素之後立即插入(至少在Chrome上,根據開發工具),而是以這種方式附加一個'script'元素觸發* asynchronous *操作下載腳本。 – 2012-03-07 18:02:25

回答

5

是的,這是強制腳本在頁面解析期間加載的唯一方法。或者至少,我願意相信的唯一方式就是跨瀏覽器。

如果你的腳本是這樣的,我能看到你的想法:

<script> 
var x = document.createElement("script"); 
x.src = "console.log.1.js"; 
x.async = false; 
x.defer = false; 
document.body.appendChild(x); 
</script> 
<script><!-- note the new script element --> 
console.log("2"); 
console.log("3"); 
</script> 

...因爲從理論上講,當解析器碰到script元素,它暫停一切(因爲有可能是document.write語句)並調用JavaScript層。所以你可能會想,在這個時候在body的末尾添加一個script元素將會在兩者之間插入。

但通過appendChild添加script元素是根本上的不同,它是由自然的異步操作(代碼繼續在腳本下載,這是不符合的標記禁止的deferasync屬性script元素的情況下)。我不能指出任何一個規格說明爲什麼,但你看到的行爲正是我所期望的。與標記內嵌的script元素的處理有點特別。

我們可以看到,它的下載軟件,通過比較使用script元素與內嵌內容的結果是問題  —至少在Chrome   —。

使用外部文件(live copy | live source):

<script> 
console.log("before"); 
(function() { 
    var s = document.createElement("script"); 
    s.src = "http://jsbin.com/avatiw"; // Logs the word "during" 
    document.body.appendChild(s); 
})(); 
</script> 
<script> 
console.log("after"); 
</script> 

結果:

before 
after 
during

使用內嵌腳本(live copy | live source   —請注意,我沒有試圖讓這個跨瀏覽器,它適用於Chrome和Firefox,因爲它們支持script元素上的text屬性):

<script> 
console.log("before"); 
(function() { 
    var s = document.createElement("script"); 
    s.text = "console.log('during');"; 
    document.body.appendChild(s); 
})(); 
</script> 
<script> 
console.log("after"); 
</script> 

輸出:

before 
during 
after
+0

你有什麼指針,規格等,或者是否來自經驗? :)可能最好的地方是看着firefox/chrome的實際源代碼,但這聽起來很痛苦。 – Karolis 2012-03-07 17:50:40

+0

@Karolis:我真的沒有什麼可以指出的,這有點弱。 :-)我用更多的討論更新了答案,fwiw。 – 2012-03-07 18:00:47

+0

我相信這是暗示的HTML5規範。 http://www.w3.org/TR/html5/embedded-content-0.html#dom-document-write – 2012-03-07 18:01:25

0

其實,我發現,使用LazyLoad插件,很適合這種使用情況,即

if (typeof jQuery === 'undefined') 
    LazyLoad.js('//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js', function() { 
     initialize(); 
    }); 
else 
    initialize();