本文深入解析ensure库如何跨浏览器动态加载JavaScript与CSS文件。通过区分Safari、IE、Firefox等浏览器的特性,分别采用script标签插入、XHR读取eval或link标签注入等方式实现加载。重点讨论了IE6和Safari2的特殊处理机制,确保脚本在全局上下文执行及样式正确应用。
ensure库功能概览
在介绍ensure内部实现机制之前,我们先观察其基本功能表现。
ensure({
html: "popup.html",
javascript: "popup.js",
css: "popup.css"
}, function() {
Popup.show("hello world");
}
);
上述代码展示了ensure的核心用法:它首先检查popup.html、popup.js和popup.css这三个资源是否已加载。若未加载,则动态引入;若已存在,则跳过加载步骤。待所有资源就绪后,ensure会执行后续传入的匿名回调函数,即执行Popup.show("hello world");逻辑。
接下来,我们将深入剖析ensure实现JavaScript与CSS动态加载的具体流程。
JavaScript动态加载实现
JavaScript加载策略
在ensure库中,JavaScript的加载逻辑根据浏览器类型分为两种执行路径:Safari浏览器与其他非Safari浏览器。
IE、Firefox与Opera中的JavaScript加载
对于IE、Firefox和Opera这三类浏览器,加载JavaScript的标准做法是创建一个script元素,将其src属性指向目标URL,最后将该元素追加到head节点中。这一过程由HttpLibrary.createScriptTag()函数负责实现。此外,为了准确获知加载完成时机,代码还利用了script元素的onload事件或onreadystatechange事件进行监听。
Safari中的JavaScript加载
由于Safari 2版本不支持onload或onreadystatechange事件,ensure采取了替代方案:通过XHR(XMLHttpRequest)将URL内容读取回来,随后手动调用eval执行这段代码。这种机制带来了一个显著限制:仅允许加载同源域的JavaScript文件。在ensure内部,该eval操作由HttpLibrary.globalEval()函数处理。为了保证JavaScript代码能在全局(global)上下文中正确执行,ensure依然采用创建script元素的方法,将待eval的代码包裹其中,最后追加至head元素内。
细心的读者可能会疑惑,为何HttpLibrary.globalEval()采用这种复杂设计,而非直接使用window.eval或eval.call。原因在于,在IE6环境下,这两种直接调用方式无法实现与script标签加载完全一致的效果,它们在IE6中并非在全局上下文中执行。查阅相关技术讨论可知,jQuery早期曾尝试使用window.execScript()解决此问题,但最终社区共识认为添加script元素是最佳的跨浏览器解决方案。因此,目前的jQuery和ensure均采用了这一实现方式。
CSS动态加载实现
CSS加载策略
相较于JavaScript,CSS的动态加载更为简单,且方法类似:只需在head元素中直接插入link元素即可。这正是loadCSS()函数所承担的工作。
值得注意的是,ensure并未强制等待CSS加载完成后再执行后续逻辑。这主要基于一个假设:浏览器能够在CSS加载完毕后自动将其应用到页面上,因此Omar AL Zabir认为CSS的加载顺序并不关键。不过,如果CSS加载速度过慢,确实可能影响页面的最终显示效果。
IE6中的CSS加载特殊处理
在此场景下,需要特别关注的对象是IE6,而非Safari。当向head元素添加link元素时,IE6要求在window的上下文中完成操作。因此,负责添加link元素的函数通过call方法切换了执行上下文,以适配IE6的要求。
总结
总结
总体而言,动态加载JavaScript与CSS在大多数情况下并不复杂,通常只需向head元素追加对应的子元素即可。主要需要特殊照顾的是Safari 2和IE6这两款较老的浏览器,需针对其特性进行特定处理。
官方地址
1
2下一页阅读全文