国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

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

2019-11-20 10:46:23
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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

代碼準(zhǔn)備:

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

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

1 動(dòng)態(tài)腳本

1.1動(dòng)態(tài)腳本的執(zhí)行時(shí)機(jī)問(wèn)題

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

dynamic1.js

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

dynamic2.js

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

dynamic3.js

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

1.1.1 DEMO1:動(dòng)態(tài)腳本的執(zhí)行時(shí)機(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">點(diǎn)擊一下</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個(gè)動(dòng)態(tài)腳本文件加入到HTML的<head>標(biāo)簽中,同時(shí)通過(guò)與正常外部腳本和內(nèi)部腳本的執(zhí)行來(lái)進(jìn)行比較,我們看一下不同瀏覽器中的執(zhí)行結(jié)果:

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

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

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

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

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

1.1.2 DEMO2:動(dòng)態(tài)腳本對(duì)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延遲腳本,無(wú)論正常外部腳本延遲了多長(zhǎng)時(shí)間,defer腳本還是會(huì)在正常外部腳本之后執(zhí)行的,但是動(dòng)態(tài)腳本卻不是這樣了,我們看一下修改后的代碼在瀏覽器中的執(zhí)行順序:


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

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

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

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

我們知道,defer腳本是有著相對(duì)明確的執(zhí)行時(shí)機(jī)的,即頁(yè)面解析完成之后,DOMContentLoaded觸發(fā)之前加載并且執(zhí)行,事實(shí)上,二者之間在執(zhí)行時(shí)機(jī)上并不存在什么關(guān)聯(lián),但是在實(shí)際實(shí)驗(yàn)中發(fā)現(xiàn),動(dòng)態(tài)腳本可能會(huì)在defer腳本之前或者之后執(zhí)行,但卻不會(huì)打斷defer腳本的執(zhí)行,我們?cè)僖搿稙g覽器環(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">點(diǎn)擊一下</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é)果可能會(huì)變化

我們?cè)黾恿藥讉€(gè)defer的腳本,再來(lái)看一下各個(gè)瀏覽器中的執(zhí)行結(jié)果:

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

1.2 動(dòng)態(tài)腳本執(zhí)行問(wèn)題總結(jié)

我們?cè)賮?lái)總結(jié)一下動(dòng)態(tài)腳本的執(zhí)行問(wèn)題:

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

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

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

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

2 Ajax注入腳本

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

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

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

我們?cè)偬砑?個(gè)外部文件:

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">點(diǎn)擊一下</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個(gè)注入腳本,通過(guò)正常引入的腳本作為參照,我們看一下在瀏覽器中的執(zhí)行結(jié)果:

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

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

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

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

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

[4]由于上述的幾點(diǎn),Ajax注入的腳本可能會(huì)阻塞DOMContentLoaded,也可能會(huì)阻塞window.onload。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿城市| 中牟县| 阿拉善右旗| 大方县| 昌都县| 贡嘎县| 赤城县| 确山县| 鄂州市| 蒙山县| 安龙县| 汉寿县| 东平县| 临汾市| 三江| 安陆市| 枞阳县| 托里县| 子洲县| 临沭县| 乡城县| 尚志市| 宿州市| 和政县| 威远县| 庄浪县| 藁城市| 高青县| 来安县| 望江县| 上饶县| 安岳县| 辛集市| 曲周县| 盐津县| 哈巴河县| 荆门市| 信阳市| 莱州市| 安仁县| 新密市|