欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之動態(tài)腳本與Ajax腳本注入

 更新時間:2016年01月19日 09:22:38   作者:TracyLin  
這篇文章主要介紹了瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之動態(tài)腳本與Ajax腳本注入 的相關(guān)資料,需要的朋友可以參考下

在《瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之defer與async特性》中,我們研究了延遲腳本(defer)和異步腳本(async)的執(zhí)行時機(jī)、瀏覽器支持情況、瀏覽器bug以及其他的細(xì)節(jié)問題。而除了defer和async特性,動態(tài)腳本和Ajax腳本注入也是兩種常用的創(chuàng)建無阻塞腳本的方法??偟膩砜?,這兩種方法都能達(dá)到腳本加載不影響頁面解析和渲染的作用,但是在不同的瀏覽器中,這兩種技術(shù)所創(chuàng)建的腳本的執(zhí)行時機(jī)還是有一定差異,今天我們再來探討一下通過動態(tài)腳本技術(shù)和Ajax注入的腳本在這些方面的特性。

代碼準(zhǔn)備:

我們使用《瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之代碼執(zhí)行順序》2.3節(jié)中的loadScript函數(shù)來添加動態(tài)腳本,同時使用這篇文章2.4節(jié)中的loadXhrScript函數(shù)來實現(xiàn)Ajax腳本注入。我們把這兩個函數(shù)都放在util.js中。

另外,本文使用的CHROME的版本為47.0.2526.80,firefox的版本為43.0.4,opera版本為30.0.1835.125。

1 動態(tài)腳本

1.1動態(tài)腳本的執(zhí)行時機(jī)問題

我們在《瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之defer與async特性》中2.3節(jié)DEMO的基礎(chǔ)上,增加三個外部js文件:

dynamic1.js

test += "我是head外部動態(tài)腳本\n";

dynamic2.js

test += "我是body外部動態(tài)腳本\n";

dynamic3.js

test += "我是底部外部動態(tài)腳本\n";

1.1.1 DEMO1:動態(tài)腳本的執(zhí)行時機(jī)初探

HTML的代碼為:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-"/>
<title>Dynamic Script Test</title>
<script src="http://lib.sinaapp.com/js/jquery/../jquery-...min.js"></script>
<script src="util.js"></script>
<script type="text/javascript">var test = "";</script>
<script>
loadScript("dynamic.js");
</script>
<script>
test += "我是head內(nèi)部腳本\n";
</script>
<script src=".js" type="text/javascript"></script>
</head>
<body>
<button id="test">點擊一下</button>
<script>
loadScript("dynamic.js");
</script>
<script src=".js" type="text/javascript"></script>
</body>
<script>
loadScript("dynamic.js");
</script>
<script src=".js" type="text/javascript"></script>
<script>
$(function(){
test += "我是DOMContentLoaded里面的腳本\n";
})
window.onload = function(){
test += "我是window.onload里面的腳本\n";
var button = document.getElementById("test");
button.onclick = function(){
console.log(test);
}
}
</script> 

在代碼中,我們先后將3個動態(tài)腳本文件加入到HTML的<head>標(biāo)簽中,同時通過與正常外部腳本和內(nèi)部腳本的執(zhí)行來進(jìn)行比較,我們看一下不同瀏覽器中的執(zhí)行結(jié)果:

注:firefox和opera中執(zhí)行結(jié)果可能會變化

從上面的例子中,我們可以看出,在不同瀏覽器中,動態(tài)腳本的執(zhí)行時機(jī)差異還是比較大的,但以下兩點是可以明確的:

[1]動態(tài)腳本確實可以起到不阻塞后續(xù)腳本的作用,即延遲作用,但是這個延遲作用卻不一定能夠持續(xù)到所有的正常腳本都執(zhí)行完畢之后,也無法保證能夠延遲到DOMContentLoaded之后

[2]動態(tài)腳本執(zhí)行的先后順序是無法保證的,這一點在http://www.dbjr.com.cn/article/77920.htm這篇文章以及后續(xù)的幾篇文章中進(jìn)行了詳細(xì)的解釋

從這個DEMO中還可以看出,動態(tài)腳本的執(zhí)行時機(jī)具有較大的不確定性,雖然在DEMO1中,動態(tài)腳本都在DOMContentLoaded事件之后執(zhí)行,但卻也并不意味著動態(tài)腳本就不會阻塞DOMContentLoaded,我們通過DEOM2來看一下:

1.1.2 DEMO2:動態(tài)腳本對DOMContentLoaded的阻塞

我們把DEMO1中的第27行內(nèi)碼修改為:

<script src="/delayfile.php?url=http://localhost/js/load/3.js&delay=5" type="text/javascript"></script> 

我們利用《瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之代碼執(zhí)行順序》中的delayfile.php,將3.js的返回延遲5秒鐘,我們知道,如果是defer延遲腳本,無論正常外部腳本延遲了多長時間,defer腳本還是會在正常外部腳本之后執(zhí)行的,但是動態(tài)腳本卻不是這樣了,我們看一下修改后的代碼在瀏覽器中的執(zhí)行順序:


注:firefox和opera中執(zhí)行結(jié)果可能會變化

可以看到,在某個正常腳本加載時間較長的時候,動態(tài)腳本的執(zhí)行明顯提前,無論在IE還是CHROME、firefox和opera中,均在DOMContentLoaded之前執(zhí)行,因此我們可以初步判斷,動態(tài)腳本的執(zhí)行時機(jī)是不確定的,在不同瀏覽器的執(zhí)行時機(jī)也都存在差異,但總的來看應(yīng)該是在代碼加載結(jié)束之后,并且線程中沒有JavaScript代碼執(zhí)行的某個時間,但不同瀏覽器對這個時間有著不同的把握。

因此,動態(tài)腳本是否會阻塞DOMContentLoaded也是不確定的,因為動態(tài)腳本可能在DOMContentLoaded觸發(fā)之前,也可能在觸發(fā)之后執(zhí)行。而且由于IE<=8不支持真正的DOMContentLoaded事件,jQuery在IE<=8中也是模擬判斷該事件的發(fā)生(下一篇會專門講解DOMContentLoaded事件),一定程度上也會對我們上述代碼的執(zhí)行結(jié)果造成影響。

1.1.3 DEMO3:動態(tài)腳本與defer

我們知道,defer腳本是有著相對明確的執(zhí)行時機(jī)的,即頁面解析完成之后,DOMContentLoaded觸發(fā)之前加載并且執(zhí)行,事實上,二者之間在執(zhí)行時機(jī)上并不存在什么關(guān)聯(lián),但是在實際實驗中發(fā)現(xiàn),動態(tài)腳本可能會在defer腳本之前或者之后執(zhí)行,但卻不會打斷defer腳本的執(zhí)行,我們再引入《瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之defer與async特性》中2.3節(jié)的DEMO中的defer腳本,修改HTML代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-"/>
<title>Dynamic Script Test</title>
<script src="http://lib.sinaapp.com/js/jquery/../jquery-...min.js"></script>
<script src="util.js"></script>
<script>
$(function(){
test += "我是DOMContentLoaded里面的腳本\n";
})
window.onload = function(){
test += "我是window.onload里面的腳本\n";
var button = document.getElementById("test");
button.onclick = function(){
console.log(test);
}
}
</script>
<script type="text/javascript">var test = "";</script>
<script>
loadScript("dynamic.js");
</script>
<script>
test += "我是head內(nèi)部腳本\n";
</script>
<script src="defer.js" type="text/javascript" defer="defer"></script>
<script src=".js" type="text/javascript"></script>
</head>
<body>
<button id="test">點擊一下</button>
<script>
loadScript("dynamic.js");
</script>
<script src="defer.js" type="text/javascript" defer="defer"></script>
<script src=".js" type="text/javascript"></script>
</body>
<script>
loadScript("dynamic.js");
</script>
<script src="defer.js" type="text/javascript" defer="defer"></script>
<script src=".js" type="text/javascript"></script>
</html> 

注:firefox和opera中執(zhí)行結(jié)果可能會變化

我們增加了幾個defer的腳本,再來看一下各個瀏覽器中的執(zhí)行結(jié)果:

從實驗結(jié)果可以看出,動態(tài)腳本的執(zhí)行時機(jī)與defer腳本并沒有直接的關(guān)系,表面上看起來在CHROME和firefox中,延遲腳本總是在動態(tài)腳本之前執(zhí)行,在《前端優(yōu)化-Javascript篇(2.異步加載腳本)》一文中提到過“ScriptDOM和defer同時都可以執(zhí)行,在不同瀏覽器中它們的優(yōu)先級的不一樣的。在Firfox和Chrome中,ScriptDOM的優(yōu)先級比defer低,而在IE中情況則相反。”,其實這種優(yōu)先級應(yīng)該是不存在的,我們只需要將defer腳本加一個加載延遲,那么動態(tài)腳本的執(zhí)行就會先于defer腳本了。

1.2 動態(tài)腳本執(zhí)行問題總結(jié)

我們再來總結(jié)一下動態(tài)腳本的執(zhí)行問題:

[1]首先,動態(tài)腳本確實能夠在一定程度上起到延遲腳本執(zhí)行的作用,但由于動態(tài)腳本的執(zhí)行時機(jī)的不確定性,這種延遲作用的效果也是未知的。

[2]其次,動態(tài)腳本的執(zhí)行順序不一定會按照添加的順序,這是動態(tài)腳本技術(shù)比較大的問題之一,最簡單的解決方式就是使用回調(diào)函數(shù),監(jiān)聽腳本的加載狀態(tài),在一個腳本加載結(jié)束后再動態(tài)添加下一個腳本。

[3]動態(tài)腳本沒有確切的執(zhí)行時機(jī),當(dāng)通過DOM的appendChild、insertBefore等方法將script元素添加到DOM中時,就會去加載JS腳本,腳本的執(zhí)行應(yīng)該是在加載結(jié)束后的某個時機(jī),不同瀏覽器對這個時機(jī)的處理差異比較大,比如在IE中,應(yīng)該是采取盡快執(zhí)行的策略,也就是在加載結(jié)束后盡快尋找時機(jī)執(zhí)行代碼

[4]動態(tài)腳本可能會在DOMContentLoaded觸發(fā)之前或者之后執(zhí)行,因此無法確定其是否會阻塞DOMContentLoaded。而在一般情況下,動態(tài)腳本都會阻塞window.onload,但是也會存在動態(tài)腳本在window.onload觸發(fā)之后執(zhí)行,從而不會阻塞window.onload

2 Ajax注入腳本

2.1Ajax注入腳本的執(zhí)行時機(jī)問題

Ajax腳本注入技術(shù)有兩種模式:同步加載和異步加載,同步加載的情況比較簡單,腳本的加載和執(zhí)行會阻塞后面代碼的執(zhí)行,直到注入的代碼被加載和執(zhí)行完畢。我們主要討論異步模式下的情況:

2.1.1 DEMO4:Ajax注入腳本的執(zhí)行問題初探

我們再添加3個外部文件:

ajax1.js

test += "我是head外部AJAX腳本\n";

ajax2.js

test += "我是body外部AJAX腳本\n";

ajax3.js

test += "我是底部外部AJAX腳本\n";

HTML的代碼為:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-"/>
<title>Ajax Script Test</title>
<script src="http://lib.sinaapp.com/js/jquery/../jquery-...min.js"></script>
<script src="util.js"></script>
<script type="text/javascript">var test = "";</script>
<script>
$(function(){
test += "我是DOMContentLoaded里面的腳本\n";
})
window.onload = function(){
test += "我是window.onload里面的腳本\n";
var button = document.getElementById("test");
button.onclick = function(){
console.log(test);
}
}
</script>
<script>
loadXhrScript("ajax.js",true);
</script>
<script>
test += "我是head內(nèi)部腳本\n";
</script>
<script src=".js" type="text/javascript"></script>
</head>
<body>
<button id="test">點擊一下</button>
<script>
loadXhrScript("ajax.js",true);
</script>
<script src=".js" type="text/javascript"></script>
</body>
<script>
loadXhrScript("ajax.js",true);
</script>
<script src=".js" type="text/javascript"></script>
</html> 

在這段代碼中,我們分別在<head>標(biāo)簽內(nèi)部、<body>標(biāo)簽內(nèi)部、<body>標(biāo)簽外部共添加了3個注入腳本,通過正常引入的腳本作為參照,我們看一下在瀏覽器中的執(zhí)行結(jié)果:

注:firefox、opera、IE中的執(zhí)行結(jié)果可能會變化

從這個執(zhí)行結(jié)果中,我們就可以看到,Ajax注入腳本的執(zhí)行時機(jī)具有更大的不確定性,事實上,與動態(tài)腳本類似,Ajax注入腳本的加載過程也是異步的,因此,完成加載的時間首先是不確定的,其次,瀏覽器在腳本加載完成后何時執(zhí)行加載的代碼同樣也是不確定的,對于異步模式下的Ajax注入腳本的執(zhí)行時機(jī),我們總結(jié)如下:

[1]Ajax注入的腳本也具有一定的延遲作用,但是與動態(tài)腳本類似,延遲的時間是不確定的。

[2]Ajax注入腳本的執(zhí)行順序是無序的,雖然DEMO4中的例子看起來注入的腳本都是按照添加的順序執(zhí)行的,但是只要稍微理解異步以及動態(tài)腳本執(zhí)行順序問題,就應(yīng)該能夠明白這一點。

[3]Ajax注入腳本的執(zhí)行時機(jī)也是不確定的,與腳本的加載時間以及瀏覽器的處理機(jī)制有關(guān)。

[4]由于上述的幾點,Ajax注入的腳本可能會阻塞DOMContentLoaded,也可能會阻塞window.onload。

相關(guān)文章

  • js實現(xiàn)選項卡效果

    js實現(xiàn)選項卡效果

    這篇文章主要為大家詳細(xì)介紹了js實現(xiàn)選項卡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • IE與Firefox在JavaScript上的7個不同句法分享

    IE與Firefox在JavaScript上的7個不同句法分享

    盡管那需要用長串的、沉悶的不同分支代碼來應(yīng)付不同瀏覽器的日子已經(jīng)過去,偶爾還是有必要做一些簡單的區(qū)分和目標(biāo)檢測來確保某塊代碼能在用戶的機(jī)器上正常運行
    2011-10-10
  • js中javascript:void(0) 真正含義

    js中javascript:void(0) 真正含義

    在javascript中javascript:void(0)經(jīng)常會用到,大家知道此含有嗎,在Javascript中void是一個操作符,該操作符指定要計算一個表達(dá)式但是不返回值,本文給大家介紹js中javascript:void(0) 真正含義,需要的朋友可以參考下
    2015-08-08
  • js提示框替代系統(tǒng)alert,自動關(guān)閉alert對話框的實現(xiàn)方法

    js提示框替代系統(tǒng)alert,自動關(guān)閉alert對話框的實現(xiàn)方法

    下面小編就為大家?guī)硪黄猨s提示框替代系統(tǒng)alert,自動關(guān)閉alert對話框的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • 特想搞點新的創(chuàng)意出來-立體方塊

    特想搞點新的創(chuàng)意出來-立體方塊

    特想搞點新的創(chuàng)意出來-立體方塊...
    2007-06-06
  • JavaScript canvas實現(xiàn)代碼雨效果

    JavaScript canvas實現(xiàn)代碼雨效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript canvas實現(xiàn)代碼雨效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • js判斷樣式className同時增加class或刪除class

    js判斷樣式className同時增加class或刪除class

    用正則表達(dá)式判斷多個class之間是否存在真正的class(前后空格的處理)然后增加class刪除class,本文給予實現(xiàn)方法,感興趣的朋友可以了解下,或許對你有所幫助
    2013-01-01
  • 再論Javascript的類繼承

    再論Javascript的類繼承

    說到Javascript的類繼承,就必然離不開原型鏈,但只通過原型鏈實現(xiàn)的繼承有著不少缺陷。
    2011-03-03
  • js判斷輸入字符串是否為空、空格、null的方法總結(jié)

    js判斷輸入字符串是否為空、空格、null的方法總結(jié)

    下面小編就為大家?guī)硪黄猨s判斷輸入字符串是否為空、空格、null的方法總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • javascript實現(xiàn)發(fā)送短信驗證碼案例

    javascript實現(xiàn)發(fā)送短信驗證碼案例

    這篇文章主要為大家詳細(xì)介紹了javascript實現(xiàn)發(fā)送短信驗證碼案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07

最新評論