加载文件CSS文件动态加载(续)—— 残酷的真相

上班之余抽点时光出来写写博文,希望对新接触的朋友有帮助。今天在这里和大家一起学习一下加载文件

    note:本文重要参考了Stoyan Stefanov的文章《When is a stylesheet really loaded?

    在之前的文章《CSS文件态动加载》中,我们提到了在态动加载CSS文件的时候,如何检测加载是否是成完。意注,这里的加载成完包含了两种情况:

    1)加载功成 2)加载失败

    也就是说,这里并没有将功成与失败的情况辨别开来。看到这里你可能困惑了,就态动加载个CSS文件,洋洋洒洒写了一两百行代码,连是否是加载功成/失败都没能辨别开来,这仿佛有些可不懂得。

    

美妙的假象——如何断判CSS加载成完

    这里先不抛出论断,而是先思考一个问题:如何态动加载CSS文件

    很单简,就上面几行代码:

var node = document.createElement('link');
node.rel = 'stylesheet';
node.href = 'style.css';
document.getElementsByTagName('head')[0].appendChild(node);
很好,那么接来下的问题是: 怎么断判CSS文件是否是加载成完

    那还不单简,几行代码就搞定的情事,前端的老朋友onload、onerror闪亮退场:

var node = document.createElement('link');
node.rel = 'stylesheet';
node.type = 'text/css'; node.href
= 'style.css'; node.onload = function(){ alert('加载功成啦!'); }; node.onerror = function(){ alert('加载失败啦!'); }; document.getElementsByTagName('head')[0].appendChild(node);
嗯,这么写是没错。。。从理论上。。。看下HTML 5里关于资源加载成完的述描,归纳综合起来就是:

    

  1. CSS文件加载功成,在link节点上触发load件事
  2. CSS文件加载失败,在link节点上触发error件事

    

    Once the attempts to obtain the resource and its critical subresources are complete, the user agent must, if the loads were successful, queue a task to fire a simple event named load at the link element, or, if the resource or one of its critical subresources failed to completely load for any reason (e.g. DNS error, HTTP 404 response, a connection being prematurely closed, unsupported Content-Type), queue a task to fire a simple event named error at the linkelement. Non-network errors in processing the resource or its subresources (e.g. CSS parse errors, PNG decoding errors) are not failures for the purposes of this paragraph.

    

    看上去很美妙的模样。我们晓得,这个界世从来都不美完,最少对于前端说来,这个界世跟美完这个词没半毛钱关系。JS中始终为人诟病的语法,浏览器糟的兼容性问题神马的。将上面那段代码放到IE(本版9及以下,10没有测过)面里,将文件接链向指一个不存在的文件,比如在fiddler里将返回替换成404:

var node = document.createElement('link');
node.href = 'none_exist_file.css';  //其他性属设置略省
node.onload = function(){
    alert('加载功成啦!');
};
node.onerror = function(){
    alert('加载失败啦!');
};
document.getElementsByTagName('head')[0].appendChild(node);
于是你看到一句丽华丽的提示:

    

    “加载功成啦!”

    

    看到这里是否是对这个界世产生了深深的困惑——我认承我时当把软微开辟IE浏览器的兄弟们家全都问候了一下。

    好吧,这篇文章是不并关于IE的吐槽文,在CSS文件加载态状的检测这个问题上,IE的表示虽不美完,但相比之下还不算别特糟。

    慢着!意思是——还有更糟的?是的,比如初期本版的firefox,连onload都不撑支。

 

    

如何断判CSS文件加载成完——五种计划

    抛开一切的怨埋与不满,按照过往的教训,如何断判一个文件是否是加载成完?一般有以下几种方法:

    

  1. 监听link.load
  2. 监听link.addEventListener('load', loadHandler, false);
  3. 监听link.onreadystatechange
  4. 监听document.styleSheets的化变
  5. 通过setTimeout时定检查你先预建创好的签标的款式是否是发生化变(该签标付与了在态动加载的CSS文件里才声明的款式)

 示例代码如下:

//计划一
link.onload = function(){
    alert('CSS onload!');
}
//计划二
link.addEventListener('load', function(){
    alert('addEventListener loaded !');
}, false);
//计划三
link.onreadystatechange = function(){
    var readyState = this.readyState;
    if(readyState=='complete' || readyState=='loaded'){
        alert('readystatechange loaded !');
    }
};
//计划四
var curCSSNum = document.styleSheets.length;
var timer = setInterval(function(){
    if(document.styleSheets.length>curCSSNum){
        //意注:当你一次性加载很多文件的时候,要需断判究竟是哪个文件加载成完了
        alert('document.styleSheets loaded !');
        clearInterval(timer);
    }
}, 50);
var div = document.createElement('div');
div.className = 'pre_defined_class';    //加载的CSS文件里才有的款式
var timer = setTimeout(function(){
    //假设getStyle方法的作用:获得签标特性款式的值
    if(getStyle(div, 'display')=='none'){
        alert('setTimeout check style loaded !');
        return;
    }
    setTimeout(arguments.callee, 50);    //续继检查
}, 50);

 

    

五种计划的际实测试结果

    际实测试的结果如何呢?如下:

    每日一道理
这浓浓的母爱使我深深地认识到:即使你是一只矫健的雄鹰,也永远飞不出母爱的长空;即使你是一条扬帆行驶的快船,也永远驶不出母爱的长河!在人生的路上不管我们已走过多远,还要走多远,我们都要经过母亲精心营造的那座桥!

    

浏览器检查onload(onload/addEventListener)link.onreadystatechange检查document.styleSheets.length检查特定签标的款式
IEok,但404等情况也会触发onload

可行,但404等情况下readyState

也为complete或loaded

 测试结果与网上说的不一致

需再加验证

ok
chrome

1、老本版:not ok

2、新本版:ok(如24.0)

 not okok(文件加载成完后才变改length) ok 
firefox

1、老本版:not ok(3.X)

2、新本版:ok(如16.0)

 not ok not ok(节点插入时,length就变改)ok 
safari

1、老本版:not ok(?)

2、新本版:ok(如6.0) 

 not ok ok(文件加载成完后才变改length)ok 
operaok not ok  not ok(节点插入时,length就变改)ok

 

     

 

 

 

 

 

 

 

 

 

    计划一、计划二本质上是一样的;而如果可能的话,stoyan议建尽可能不必计划五,原因如下:

    1)性能销开(计划四也好不到哪去)

    2)需添加额定无用款式,要需对CSS文件有充足的控制权(CSS文件可能是不并自己的队团在护维)

    那好,时暂将计划五消除在外(其实兼容性是最好的),从上表格可以晓得,各浏览器别分可采取计划如下:

    

浏览器可采取计划
IE计划一、计划二、计划三
chrome计划四
firefox
safari计划四
opera计划一、二

 

 

 

 

 

    firefox竟然。。。霎时光心坎万千只草泥马在欢快地奔腾。。。对于firefox,stoyan大神也尝试了其他方法,比如:

    1、MozAfterPaint(这是神马还没查,总之失败了,求导指~)

    2、document.styleSheets[n].cssRules,只有当CSS文件加载来下的时候,document.styleSheets[n].cssRules才会发生化变;但是,由于ff 3.5的全安制限,如果CSS文件跨域的话,JS拜访document.styleSheets[n].cssRules会错出

    

 

    

如在何老本版的firefox里断判CSS是否是加载成完

    就在stoyan大神即将失望之际,Zach Leatherman 童鞋发现了firefox下的处理计划

    

    

  1. you create a style element, not a link
  2. add @import "URL"
  3. poll for access to that style node's cssRules collection

    

    这个计划利用了上面提到的第二点,同时处理了跨域的问题。代码如下(代码引用自原文):

var style = document.createElement('style');
style.textContent = '@import "' + url + '"';
 
var fi = setInterval(function() {
  try {
    style.sheet.cssRules; // <--- MAGIC: only populated when file is loaded
    CSSDone('listening to @import-ed cssRules');
    clearInterval(fi);
  } catch (e){}
}, 10);  
 
head.appendChild(style);
根据stoyan、Zach的路思,  Ryan Grove 在LazyLoad里将现实,有趣兴的可以看下  源代码 

    Ryan Grove的代码有些小问题,比如:

    1、CSS文件的阻塞式加载,比如加载A.css、B.css,要需等A.css加载完了,才开始加载B.css

    2、某些断判语句的失误,致导CSS文件记录功成的情况下,检测失误(见pollWebkit方法第一个while环循)

    尽管如此,还是要感激Ryan的动劳(撒花),LZ根据际实要需,将LazyLoad里js加载分部的代码剔除,并上面提到的两个较比显明的bug fix了,修改后的源码以及demo可见参《CSS文件态动加载》一文 :)

 

    

如何断判CSS文件加载失败

    始终到这里,我们于终处理了如何检测CSS文件是否是加载成完的问题。 接来下又有一个峻严的问题摆在我们眼前:如何断判一个文件加载失败?

    不要忘了onerror童鞋!onerror的撑支情况如何呢?—— 际实测试了下,情况其实不悲观,直接引用先辈的动劳结晶,原文接链如下:http://seajs.org/tests/research/load-js-css/test.html

    

    

    css

    

    : Chrome / Safari: -

    WebKit >= 535.23 后撑支 onload / onerror

    - 之前的本版无任何件事触发 Firefox: -

    Firefox >= 9.0 后撑支 onload / onerror

    - 之前的本版无任何件事触发 Opera: - 会触发 onload -

    但 css 404 时,不会触发 onerror

    IE6-8: -

    下载功成和失败时都市触发 onload 和 onreadystatechange,无 onerror

    IE9: - 同 IE6-8 - onreadystatechange 会重复触发 处理计划: - Old WebKit 和 Old Firefox 下,用 poll 方法:

    load-css.html

    - 其他浏览器用 onload / onerror 足不: -

    Opera 下如果 404,没有任何件事触发,有可能致导赖依该 css 的模块始终处于等待态状

    - IE6-8 下辨别不出 onerror - poll 探测难以辨别出 onerror

    

    可见,之前的计划,其实不能美完处理“断判CSS文件加载失败”这个问题(当相使人丧沮,有主张的童鞋千万要留言告诉我 TAT)

    现在有两种路思,其实并没有全完处理问题:

    1、超时失败定判:设定t值,当加载时光过超t时,认定其加载失败(单简粗鲁,现在采取方法)

    2、定判加载成完后,通过上面的计划五(检查款式),断判CSS文件是否是加载失败 —— 提前是没有被认定为“超时失败”

    多方讨教后,外门部的事同tom供给了一个不错的的路思,该现实计划经已有线上项目作为实际撑支:JSONP

 

    

CSS加载失败断判——不一样的路思JSONP

    假设有style.css(际实想要加载的文件)、style.js;style.js里是个回调方法CSSLoadedCallback,CSSLoadedCallback做两件情事

    1)打标记,标识style.js加载功成(即面页拿到了style.css里的款式字符串)

    2)建创link签标,并将CSSLoadedCallback里传入的款式字符串写到link签标里

    style.js里的代码大致如下:

//第一个参数style.css为际实想要加载的CSS的文件名
//第二个参数:style.css里的款式
CSSLoadedCallback("style.css", ".hide{display:'none';} .title{font-size:14px;}");
 于是,由先原的断判CSS是否是加载失败,转为断判JS是否是加载失败;关于JS是否是加载失败,先辈的测试如下,原文接链请点击 这里

 关于IE6-8没法辨别onerror,在这里是不并问题(可通过断判变量是否是存在现实),就是说JSONP是个靠谱的处理计划。

    

    js: Chrome / Firefox / Safari / Opera: - 下载功成时触发 onload, 下载失败时触发 onerror - 下载功成括包 200, 302, 304 等,只要下载来下了就好 - 下载失败指没下载来下,比如 404 - Opera 老本版对 empty.js 这类空文件时不会触发 onload,新本版已无问题 IE6-8: - 下载功成和失败时都市触发 onreadystatechange, 无 onload / onerror - 功成和失败的义含同上 IE9: - 有 onload / onerror,同时也有 onreadystatechange 处理计划: - 在 Firefox、Chrome、Safari、Opera、IE9 下,用 onload + onerror - 在 IE6-8 下,用 onreadystatechange 足不: -

    IE6-8 下辨别不出 onerror

    

 

    

小结

    1、可检测CSS文件是否是加载功成(通过多种手段断判文件加载成完的情况下,结合检查签标款式的方法)

    2、可大致检测CSS文件是否是加载失败(提前是断判CSS经已加载成完,在chrome、opera老本版里没法确准断判)

    3、通过JSONP方法可确准断判文件是否是加载功成、失败

    

 写在前面

    本文参考了多篇外站术技博客的文章,若有引用外站容内,但未声明的情况,敬请指处!

     文中示例若有漏错,请指出;如认为文章对您有效,可点击“推荐” :)

    参考接链

    http://www.phpied.com/when-is-a-stylesheet-really-loaded/

    https://github.com/seajs/seajs/blob/master/src/util-request.js

    https://github.com/rgrove/lazyload/commit/6caf58525532ee8046c78a1b026f066bad46d32d

    http://www.zachleat.com/web/load-css-dynamically/

文章结束给大家分享下程序员的一些笑话语录: 打赌
飞机上,一位工程师和一位程序员坐在一起。程序员问工程师是否乐意和他一起玩一种有趣的游戏。工程师想睡觉,于是他很有礼貌地拒绝了,转身要睡觉。程序员坚持要玩并解释说这是一个非常有趣的游戏:"我问你一个问题,如果你不知道答案,我付你5美元。然后你问我一个问题,如果我答不上来,我付你5美元。"然而,工程师又很有礼貌地拒绝了,又要去睡觉。  程序员这时有些着急了,他说:"好吧,如果你不知道答案,你付5美元;如果我不知道答案,我付50美元。"果然,这的确起了作用,工程师答应了。程序员就问:"从地球到月球有多远?"工程师一句话也没有说,给了程序员5美元。  现在轮到工程师了,他问程序员:"什么上山时有三条腿,下山却有四条腿?"程序员很吃惊地看着工程师,拿出他的便携式电脑,查找里面的资料,过了半个小时,他叫醒工程师并给了工程师50美元。工程师很礼貌地接过钱又要去睡觉。程序员有些恼怒,问:"那么答案是什么呢?"工程师什么也没有说,掏出钱包,拿出5美元给程序员,转身就去睡觉了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值