谈一谈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 全线不兼容。所以暂时不予考虑