談一談CDN的JS,CSS文件載入出錯主域名重試的問題
- 2019 年 12 月 4 日
- 筆記
背景知識
了解這些基礎知識之後,我們再來談談怎麼做
檢測css是否載入出錯
目前比較靠譜的方案就是檢測某一個特定的樣式來判斷。頁面有多個css文件時我們怎麼去對應特定樣式呢?方法其實很多。
- 文件名匹配class
<link rel="stylesheet" type="text/css" href="//8.url.cn/edu/webcourse/index_e84e768.css" />
index_e84e768.css裡面有
#_e84e768{display: none;}
- link順序匹配class
<link rel="stylesheet" type="text/css" href="//cdn.xxx.com/css/a.css" /> <link rel="stylesheet" type="text/css" href="//cdn.xxx.com/css/b.css" />
a.css裡面有
.__check__css__loaded0 {display: none;}
b.css裡面有
.__check__css__loaded1 {display: none;}
通過link的順序來檢測對應的css是否載入出錯。
- 增加屬性<link rel="stylesheet" type="text/css" href="//cdn.xxx.com/css/a.css" data-checkClass="__check__css__loaded0" /> <link rel="stylesheet" type="text/css" href="//cdn.xxx.com/css/b.css" data-checkClass="__check__css__loaded1"/>
第一種方案通常要修改構建工具比較麻煩。這裡僅列出第二種方案的程式碼 僅供參考。
var checkCssLoaded = function(options) { var opts = options || {}; opts.prefix = opts.prefix ||'__check__css__loaded'; opts.cdnPath = opts.cdnPath || '//8.url.cn/edu/'; opts.replacePath = opts.replacePath || '//ke.qq.com'; var links = document.querySelectorAll('link[rel=stylesheet]'); links.forEach(function(link, index) { var div = document.createElement("div"); div.className = opts.prefix + index; div.style.cssText = "position:absolute;height:0;width:0;overflow:hidden"; document.body.appendChild(div); var flag = (window.getComputedStyle ? window.getComputedStyle(div, null).display : div.currentStyle.display) == 'none'; // console.log(link.href, flag); if (!flag) { var href = link.href; href = href.replace(opts.cdnPath, opts.replacePath); link.href = href; } }); } checkCssLoaded();
程式碼解釋:原理非常簡單。css不阻塞js的載入,但是會阻塞js的執行。所以在瀏覽器裡面css和js的執行時保證順序的。所有隻要這段程式碼在link標籤的後面執行就可以直接判斷文件是否載入完成。
ps: 這裡順便補充一下讓css不阻止頁面渲染的方法
<link href="//cdn.xxx.com/css/a.css" rel="stylesheet" media="none" onload="if(media!='all'){media='all';}">
檢測js載入是否載入出錯
如果你看過 瀏覽器 CSS/JS 載入能力測試表,那麼就很容易知道script
標籤是會觸發onload
或者onreadystatechange
(ie瀏覽器)事件的, 前面也提到了css和js的執行時保證順序的。
那麼檢測的方案就很容易了
<script type="text/javascript" src="//7.url.cn/edu/webcourse/index_944c80b.js" onreadystatechange="window.__check__js__loaded0=666;" onload="window.__check__js__loaded0=666;"></script>
js載入完成之後就會設置變數為666。然後通過判斷這個變數是否為666就可以知道js是否載入完成。 這邊也列一下js主域重試的程式碼,僅供參考, 注意這段程式碼放的位置。
var checkJSLoaded = function(options) { var opts = options || {}; opts.prefix = opts.prefix ||'__check__js__loaded'; opts.cdnPath = opts.cdnPath || '//7.url.cn/edu/'; opts.replacePath = opts.replacePath || '//ke.qq.com'; var scripts = document.querySelectorAll('script'); var index = 0; scripts.forEach(function(script) { var src = script.src; if (!src || src.indexOf(opts.cdnPath) === -1) {return;} // console.log(src, window[opts.prefix + index]); if (window[opts.prefix + index] !== 666) { src = src.replace(opts.cdnPath, opts.replacePath); var js = document.createElement('script'); js.type = script.type; js.src = src; js.async = false; script.insertBefore(js, script); script.removeChild(script); } index++; }); } checkJSLoaded();
還有一個高級的api performance.getEntriesByType('resource')
可以獲取到載入成功的所有資源。 mdn的地址: https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/getEntriesByType , 我們查一下它的兼容情況發現http://caniuse.com/#search=performance Safari, iOS Safari 全線不兼容。所以暫時不予考慮