//反面教材. //script Element + link Element(FireFox加載HTML) + object ELement (FireFox JS CSS ...) //需要在恰當時間 調用dispose()方法用來 移除過多的節點.(受Firefox 和 Opera拖累) void function (win,doc,head,ns){ var _class = '__PRELOAD_CLEARTEMPELEMENTS__' , _tag = 'script'; if(ns.preLoad){ return; } var _preLoad = ns.singlePreLoad = !!doc.getBoxObjectFor || win.mozInnerScreenX != null ? (_tag = '*') && function(sURL,isHTML){ //FF3.0+開始支持 object加載其他數據類型. 如果是html則會解析該html var el; if(isHTML){ el = doc.createElement('link'); el.type = 'text/css'; el.rel = 'stylesheet'; el.href = sURL; }else{ el = doc.createElement('object'); el.data = sURL; } el.className = _class; head.appendChild(el); }: function(sURL){//!FF var el = doc.createElement('script'); el.type = 'text/C'; el.className = _class; el.src = sURL; head.appendChild(el); }; ns.preLoad = function(aURL){ typeof aURL == 'string' && (aURL = [aURL]); for(var i = 0 , l = aURL.length ; i < l ; i++)_preLoad(aURL[i]); }; ns.preLoad.dispose = function (){ var list = ns.DOM.$C('__PRELOAD_CLEARTEMPELEMENTS__',_tag,head); for (var i = list.length ; i-- ;){ head.removeChild(list[i]); } list = null; }; }(window,document,document.getElementsByTagName('head')[0],Visit.Util);
//worker + script 方案 引入worker.js onmessage = function(e){ var a = e.data.toString().split(','); for(var i = 0 , l = a.length ;i++){ try{ //避免因加載失敗導致腳本不在繼續執行下去. 否則 一個imirtScripts.apply(null,a); 就解決問題了. //現在,還導致失去了並行加載的優勢.但是也是在是木有辦法. importScripts(a[i]); }catch(e){} } postMessage('Loaded'); }; void function (win,doc,head,ns){ var _dom = ns.DOM, _workerURL = 'js/worker.js',//worker.js Path _emptyFn = function(){}; if(ns.preLoad){ return; } if(win.Worker){//FF3.5+ Opera10+ Safari4+ Chrome3+ (需要 worker.js支持) ns.preLoad = function(aURL){ var _w = new win.Worker(_workerURL); _w.onerror = _emptyFn; _w.onmessage = function(e){ e.data == 'VISITLOADED' && (_w.terminate(),1) && (_w = null);// }; _w.postMessage(aURL); }; }else if(!doc.getBoxObjectFor || !win.opera){//IE6+ Safari3- Chrome2- ns.preLoad = function(aURL){ for(var i = 0,l = aURL.length ; i < l ; i++){ _dom.loadJS(aURL[i],null,null,'text/C'); } }; }else{//FF3.0- Opera9.6- ns.preLoad = _emptyFn; } }(window,document,document.getElementsByTagName('head')[0],Visit.Util);
最后說說為什么說Woker 的沙箱不夠好.
1.importScripts方法加載的資源如果是個腳本.那么實際上它是會執行的. 所以一旦資源擁有者了解這一切,那么可以給你一個執行 postMessage('loaded')語句的腳本.
顯然主頁面 : e.data == 'loaded' && (_w.terminate(),1) && (_w = null); 這里就會被執行.那么結果就不准確了. 雖然此漏洞可以通過 一個隨機key驗證方式繞過. 但考慮到 2 和 3 的問題.
僅僅修復。此漏洞 意義並不大. 而且 importScripts 的語句還要放到一個獨立的閉包中..額外損耗. 還沒意義.得不償失.
2. 加載的資源執行死循環的腳本.那么 除了FF 其他瀏覽器的 postMessage('loaded') 可能就無法被執行到.
3. 另外應該注意.opera 瀏覽器 worker 內部調用 self.close()后 帶來的問題...這個問題我們無法繞過去..很糾結. 不過好在 僅僅是使我們無法確定資源是否加載完畢而已...
損失可以忽略. 只要沒有安全問題.還是可以接受的.如果可能的話 加入一個 超時機制 來彌補這種問題所帶來的風險應該是ok的...畢竟我們最終的目的是為了預加載資源.
4. 一但importScripts 引入的腳本 執行類似的腳本 while(!window) postMessage('hellow'); 那么就是個悲劇 主頁面進程相當的卡.
類似的還有 importScripts()遞歸調用.
防堵這兩個問題也是有辦法的. 大家可以自己想想看(提示黑名單制度+超時制度.)
參考偽代碼 :
_w.onmessage = function(e){
win.clearTimeout(_timer);
_w.terminate();
_w = _w.onmessage = null;
e.data != key && _preLoad.addBlackList && _preLoad.addBlackList((aURL.shift(),aURL),e.data);
};
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。