­

談一談CDN的JS,CSS文件載入出錯主域名重試的問題

  • 2019 年 12 月 4 日
  • 筆記

背景知識

了解這些基礎知識之後,我們再來談談怎麼做

檢測css是否載入出錯

目前比較靠譜的方案就是檢測某一個特定的樣式來判斷。頁面有多個css文件時我們怎麼去對應特定樣式呢?方法其實很多。

  1. 文件名匹配class
<link rel="stylesheet" type="text/css" href="//8.url.cn/edu/webcourse/index_e84e768.css" />

index_e84e768.css裡面有

#_e84e768{display: none;}
  1. 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是否載入出錯。

  1. 增加屬性<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 全線不兼容。所以暫時不予考慮