用js的document.write輸出的廣告無(wú)阻塞加載的方法
一、廣告代碼分析
很多第三方的廣告系統(tǒng)都是使用document.write來(lái)加載廣告,如下面的一個(gè)javascript的廣告鏈接。
<script type="text/javascript" src="http://gg.5173.com/adpolestar/5173/
;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script>
這個(gè)javascript請(qǐng)求返回的是這樣的一段代碼:
document.write( "<a +
"ad=6FF3F844_33E6_86EE_3B96_D94C1CF1AEC4;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;" +
"pu=5173;/?http://www.7bao.com/g/xlsbz/index' target='_blank'><img src='" +
"http://html.5173cdn.com/market/yunyinga/xly132.gif' " +
"border='0' width="132px" height="58px" /></a>" );
這種看似有點(diǎn)二的加載方式,但是你卻沒(méi)辦法改造它,因?yàn)樗旧砭褪堑谌降?。并且代碼都添加了統(tǒng)計(jì)的功能,上面的javascript的廣告鏈接每請(qǐng)求一次都會(huì)統(tǒng)計(jì)一次,生成的代碼也有點(diǎn)擊統(tǒng)計(jì)的功能,也就是說(shuō)必須以這種方式來(lái)進(jìn)行加載。
document.write是在頁(yè)面渲染的時(shí)候同步進(jìn)行的,必須要等javascript代碼下載好并且document.write執(zhí)行完后才接著渲染后面的內(nèi)容,如果廣告比較多的話(huà),就會(huì)導(dǎo)致頁(yè)面阻塞,尤其是在頁(yè)面的首屏插好幾個(gè)圖片尺寸比較大的這種廣告,那么阻塞情況就相當(dāng)明顯和嚴(yán)重,會(huì)讓用戶(hù)覺(jué)得你這個(gè)網(wǎng)頁(yè)很慢。
二、重寫(xiě)document.write
為了避免阻塞,就不能讓document.write方法在頁(yè)面渲染的時(shí)候執(zhí)行,必須想辦法讓javascript的廣告代碼在DOM樹(shù)就緒(DOM ready)之后才執(zhí)行,但是在DOM樹(shù)就緒后執(zhí)行document.write會(huì)重新渲染整個(gè)頁(yè)面,這樣也是不行的。document.write雖然是瀏覽器原生的方法,但是也可以自定義一個(gè)方法來(lái)覆蓋掉原來(lái)的方法。在javascript廣告代碼加載之前,重寫(xiě)document.write,等加載并執(zhí)行完再改回來(lái)。
三、延遲加載javascript代碼
上面比較關(guān)鍵的一步,延遲加載javascript代碼,如何實(shí)現(xiàn)呢?先嘗試通過(guò)改寫(xiě)script的type屬性,比如將type設(shè)置成一個(gè)自定義的屬性”type/cache”,但這樣大部分瀏覽器(Chrome不會(huì)下載)仍然會(huì)下載這段代碼,但不會(huì)執(zhí)行,在頁(yè)面渲染的時(shí)候下載這么一段代碼仍然會(huì)阻塞,通過(guò)改寫(xiě)script的type并不能實(shí)現(xiàn)真正的延遲加載,最多能實(shí)現(xiàn)只加載不執(zhí)行,而且還存在兼容問(wèn)題。
將script標(biāo)簽放到textarea標(biāo)簽中,等需要加載的時(shí)候再讀取textarea的內(nèi)容,這樣可以實(shí)現(xiàn)真正的延遲加載script,這個(gè)方法要感謝玉伯提出的BigRender(墻外)方案。
<div>
<textarea style="display:none">
<script type="text/javascript" src="http://gg.5173.com/adpolestar/5173/
;ap=2EBE5681_1BA3_4663_FA3F_E73D2B83FBDC;ct=js;pu=5173;/?"></script>
</textarea>
</div>
延遲加載script并重寫(xiě)document.write,下面是代碼實(shí)現(xiàn):
/**
* 重寫(xiě)document.write實(shí)現(xiàn)無(wú)阻塞加載script
* @param { Dom Object } textarea元素
*/
var loadScript = function( elem ){
var url = elem.value.match( /src="([\s\S]*?)"/i )[1],
parent = elem.parentNode,
// 緩存原生的document.write
docWrite = document.write,
// 創(chuàng)建一個(gè)新script來(lái)加載
script = document.createElement( 'script' ),
head = document.head ||
document.getElementsByTagName( 'head' )[0] ||
document.documentElement;
// 重寫(xiě)document.write
document.write = function( text ){
parent.innerHTML = text;
};
script.type = 'text/javascript';
script.src = url;
script.onerror =
script.onload =
script.onreadystatechange = function( e ){
e = e || window.event;
if( !script.readyState ||
/loaded|complete/.test(script.readyState) ||
e === 'error'
){
// 恢復(fù)原生的document.write
document.write = docWrite;
head.removeChild( script );
// 卸載事件和斷開(kāi)DOM的引用
// 盡量避免內(nèi)存泄漏
head =
parent =
elem =
script =
script.onerror =
script.onload =
script.onreadystatechange = null;
}
}
// 加載script
head.insertBefore( script, head.firstChild );
};
四、圖片延遲加載的增強(qiáng)版
實(shí)現(xiàn)了無(wú)阻塞式的延遲加載javascript廣告代碼,能否進(jìn)一步優(yōu)化?如果廣告沒(méi)在首屏出現(xiàn),能否像通常的圖片的延遲加載一樣來(lái)進(jìn)行延遲加載?答案是肯定的。對(duì)我之前寫(xiě)的圖片延遲加載的小插件進(jìn)行擴(kuò)展,將原來(lái)的圖片加載方式(替換src)改成上面的loadScript方式加載就可以實(shí)現(xiàn)。當(dāng)然,僅僅是這樣的修改還是會(huì)有問(wèn)題的。如果有多個(gè)圖片,并且loadScript是同時(shí)進(jìn)行的,而document.write又是全局的方法,保不準(zhǔn)在加載A的時(shí)候不影響到B,必須讓它們一個(gè)個(gè)的按順序加載,加載完A之后才能加載B。
五、隊(duì)列控制
為了讓javascript廣告代碼按順序加載就需要一個(gè)隊(duì)列來(lái)控制加載。于是又有了下面這段簡(jiǎn)單的隊(duì)列控制代碼:
var loadQueue = [];
// 入列
var queue = function( data ){
loadQueue.push( data );
if( loadQueue[0] !== 'runing' ){
dequeue();
}
};
// 出列
var dequeue = function(){
var fn = loadQueue.shift();
if( fn === 'runing' ){
fn = loadQueue.shift();
}
if( fn ){
loadQueue.unshift( 'runing' );
fn();
}
};
圖片延遲加載器請(qǐng)參閱比文:http://www.dbjr.com.cn/article/50685.htm
相關(guān)文章
一篇文章搞定JavaScript類(lèi)型轉(zhuǎn)換(面試常見(jiàn))
這篇文章主要介紹了一篇文章搞定JavaScript類(lèi)型轉(zhuǎn)換(面試常見(jiàn)),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-01-01div失去焦點(diǎn)事件實(shí)現(xiàn)思路
blur只是針對(duì)form表單控件的,而對(duì)于 span , div , li 之類(lèi)的,則沒(méi)辦法觸發(fā)它們的動(dòng)作,本文有個(gè)示例,看看是怎么實(shí)現(xiàn)的2014-04-04JS設(shè)置時(shí)間無(wú)效問(wèn)題的解決辦法
在發(fā)送短信息驗(yàn)證碼的時(shí)候要用到j(luò)s設(shè)置時(shí)間倒序問(wèn)題,有時(shí)候會(huì)導(dǎo)致js失效問(wèn)題,怎么辦呢?今天小編給大家分享JS設(shè)置時(shí)間無(wú)效問(wèn)題的解決辦法,需要的朋友參考下吧2017-02-02Javascript 鼠標(biāo)移動(dòng)上去小三角形滑塊緩慢跟隨效果
一個(gè)tab選項(xiàng)卡,當(dāng)鼠標(biāo)移動(dòng)上去時(shí)紅色滑塊跟隨,在布局過(guò)程中經(jīng)常會(huì)使用到,本文提供了詳細(xì)的實(shí)現(xiàn)代碼,感興趣的朋友可以參考下2013-04-04js將類(lèi)數(shù)組對(duì)象轉(zhuǎn)換成數(shù)組對(duì)象
javascript與dom有許多瑕疵,如著名的類(lèi)數(shù)組對(duì)象Arguments,其他諸如HTMLCollection,NodeList如果它們都是數(shù)組的子類(lèi),那多省時(shí)啊。2010-05-05JavaScript代碼編寫(xiě)中各種各樣的坑和填坑方法
這篇文章主要介紹了JavaScript代碼編寫(xiě)中各種各樣的坑和填坑方法,相信你肯定遇到過(guò)這些陷阱,而且陷入過(guò),本文共計(jì)介紹了5種坑和填坑方法,需要的朋友可以參考下2014-06-06JavaScript實(shí)現(xiàn)的浮動(dòng)層框架用法實(shí)例分析
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的浮動(dòng)層框架用法,以實(shí)例形式分析了JavaScript實(shí)現(xiàn)可關(guān)閉的半透明浮動(dòng)層相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10關(guān)于RxJS Subject的學(xué)習(xí)筆記
這篇文章主要介紹了關(guān)于RxJS Subject的學(xué)習(xí)筆記,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12