| 文章簡介:用ControlJS最佳化阿里媽媽廣告. |
長時間以來阿里媽媽的廣告載入策略一直存在些問題,很多頁面也因為阻塞式的廣告載入而被拉低效能,影響使用者體驗。畢竟阿里媽媽廣告的渲染依賴於諸多嵌套的document.write。ControlJS的目標就是解決js的阻塞式渲染,因此靈玉急不可耐想與同仁們共同去揭秘ControlJS……
Steve Souders在2010年12月份發布了ControlJS項目,該項目是讓開發人員更好的去控制javascript檔案的下載和執行,從而提高了頁面指令碼的載入速度。
Steve提出了一個非常具有創造性的思想,就是預先非同步下載javascript檔案而不解析執行,直到需要的javascript處理時才去真正的執行。這一點得到了很多人的關注與驗證。Nicholas Zaka也因ControlJS引發了很多思考,並分析了ControlJS和LABjs 的區別所在,詳細內容可以閱讀Thoughts on script loaders和Separating JavaScript download and execution。Steve使用3篇博聞詳細介紹了ControlJS:非同步載入、順延強制、重寫document.write。
ControlJS的原理
非同步載入
ControlJS本身是非同步進行載入的,首先將script的標籤type屬性值更改為瀏覽器無法識別的類型,這樣瀏覽器不會認為這是一個指令碼。本身非同步載入的ControlJS執行時開始遍曆type=”text/cjs”的script標籤(包括內嵌指令碼),如果存在”DATA-CJSSRC”屬性將建立IMAGE或者OBJECT對象(依賴瀏覽器而選擇),去非同步預下載指令檔並快取檔案,直到window.onload時解析並執行javascript,同時第二次去遍曆遺漏的script標籤。具體操作可看Async WITH ControlJS
順延強制
瀏覽器在解析執行javascript階段是阻塞任何操作的,這時的瀏覽器處於假死狀態,Steve分析了美國的Alexa前10名網站的指令碼初始需要載入執行情況,發現只有29%是需要頁面載入時初始化解析執行的,而其他71%的指令碼是在觸發互動時才會執行,壓縮後這些腳平均載入是229 kB,未壓縮是500KB,這是個大量的資料。
我們希望的結果是在頁面載入中不去解析執行javascript,只是提前預下載好檔案。例如通用的點擊彈出二級導航,使用者有可能永遠都沒有點擊導航的行為,此時導航的功能指令碼根本毫無用處。但是人們在點擊導航時不希望等太久javascript的執行,所以ControlJS會提前下載檔案,這樣javascript只是解析執行,不會花時間放到下載檔案上。代碼一目瞭然,具體操作可看Menu WITH ControlJS
重寫document.write
在預設情況下這些非同步指令碼都是在window.onload解析執行,如果此時指令碼調用window.write方法,將導致一個不希望發生的問題,就是整個頁面被window.write的輸出內容替換,所有頁面內容將被刪除,ie下將處於停滯狀態。產生問題的原因是由於在docuemnt被載入完後調用docuemnt.write方法時將會自動去觸發document.open,寫入任何處於開啟狀態的doucment都將會會替換整個頁面的內容。這便導致目前為止所有非同步指令碼無法延遲document.write的問題,ControlJS的處理方法是重寫docuemnt.write,如下:
ControlJS建立一個dom元素(span),將其插入當前被解析執行的script標籤之前,並且設定SPAN的innerHTML的值為docuemnt.write的內容。具體操作可看document.write WITH ControlJS
用ControlJS最佳化阿里媽媽廣告
對於現在大部分的廣告形式都是採用document.write方式寫入,無法將這些內容非同步處理是開發人員非常頭疼的問題。ControlJS可以為我們解決這類煩惱。
沒有應用ControlJS的網狀圖。DEMO可以看http://chesihui.github.com/ad-demo.html
應用ControlJS最佳化後的網狀圖。DEMO可以看http://chesihui.github.com/ControlJS-demo.html
ControlJS的局限性
ControlJS存在一個問題是在document.write中多層嵌套script標籤時,頁面仍然存在觸發document.open的問題。查看原始碼發現在執行完一個javascript後都會恢複document.write的原生方法:
動態指令碼的非同步載入,同樣使得document.write方法也是非同步執行,因此不能恢複document.write的原生功能。複現的情況如 DEMO 。注釋這段指令碼雖然解決了不觸發window.open的問題,但是同樣的非同步載入執行導致無法正確定位廣告寫入的位置。對於阿里媽媽廣告設定alimama_type=”i”的時候,載入圖片廣告是根據多層document.write實現的,只能正確渲染最後一個圖片廣告。複現如 DEMO 。
因為ControlJS的非同步載入不存在任何依賴順序,所有指令碼都是並行載入執行,如果你的頁面存在太多依賴關係,ControlJS將不會適合你的項目。
最後總結ControlJS為我們做了什麼事,利弊還需要自己去權衡:
- 非同步下載所有指令碼
- 同時處理內嵌與外鏈指令碼
- 延遲指令碼的執行直到頁面被渲染完
- 允許指令碼只下載不執行
- 解決了非同步指令碼中存在docuement.write的問題
- ControlJS本身是非同步載入
原文:http://ued.taobao.com/blog/2011/03/18/controljs-alimama/
document.write = CJS.docwriteOrig;
CJS.docwriteOrig = document.write;
document.write = CJS.docwrite;