动态载入脚本和CSS
一般来说,脚本和CSS都是在页面中用<script>和<link>来进行引入,也就是说,正如你现在所看到的这张网页一样,是静态的写在html中的。
而在一些应用场合,你的某一个页面在不同场合下所需的脚本和CSS是不同的,而如果你同时把这些脚本和CSS全部载入在这张页面之中,则会显得非常庞大,而且非常笨重。
一个CSS的示例便是换肤,比如JQuery UI的ThemeRoller,通过后期载入CSS来达到覆盖原有效果的作用(对于同样的CSS效果而言,都是遵循最近原则,所以后加载的文件会覆盖之前CSS的效果)。而 JavaScript的示例便是通过页面事件触发来形成一个不同的效果。比如在你按下按钮A时,你需要显示某个UI组件A并加载a.js来激活这个组件的 UI表现功能,而在按下按钮B的时候,则对B有类似的操作。如果在A和B的脚本都很大的情况下,在页面加载之初就全部载入就会显得页面初始载入时间过长,给用户的体验就会显得不那么好。所谓的按需索取,就是这个意思(虽然这样并不是一个很好的设计,因为如果频繁使用会让JS请求增加很多,倒不如对脚本进行压缩合并做一个包来得合算,具体情况还是得具体分析)。
在很多JS的框架中都会有对JavaScript和CSS的动态加载的设定。比如在JQuery中有$.getScript(),Dojo有dojo.require(),YUI有YUILoader(YAHOO.util.YUILoader)。
一切都是xmlhttprequest
对xmlhttprequest的重新认识是AJAX技术的核心。所有的非页面加载期前后台的交互都是由它来完成的。
而对于动态载入来说,你可以选择同步加载或者异步加载。
由于JavaScript执行的时候在浏览器中是单线程操作的(至少它看上去是,特指在函数执行的过程中无法进行类似于其他语言的多线程操作),你无法进行类似于多线程阻塞或者悬停阻挡的效果。(注:alert函数其实在当前浏览器脚本的执行过程中起到了一个阻塞当前线程的效果,但它实在太丑了,而且功能过于有限,没办法起到更多的作用)所以说,如果你的需求是要在一个函数片段中执行远程载入,而且可能由于某种很恶劣的环境无法将后续代码以 callback的形式延后执行,那么你就需要将这个操作同步化。如果只是一个很简单的应用,那么异步化是个很好的主意。
同步的JavaScript基本代码:
xmlhttp.open(\"GET\",url,false/*asynchronous*/);
第三个参数指示这个请求是否是异步传输,如果是true便是异步,false便是同步。
如果你使用框架,那么请参阅相关API。
然后拿到这个请求回来的js代码之后便将之执行,也就是万恶的eval。
那么来看一下异步的处理方法吧。
var head = document.getElementsByTagName(\"head\")[0];
var script = document.createElement(\"script\");
script.src = s.url;
head.appendChild(script);
这样的写法还是很干净的,就是在head上面加一个script结点,然后让浏览器来做这么些事。或者你可以在这个script结点的onreadystatechange和onload事件中把这个结点给删了,这样,当前的DOM模型就能保证干净如初。
诚然,你也可以使用同步的同样方法来进行异步加载,但那种用法显然不及这种来得优雅,特别是当你只需要一个lib的时候。
无论是同步抑或是异步,都是采用xmlhttprequest的方式。在同步模式下,应该使用GET方法向服务端获取一个JS或者CSS文件。
另外需要讲的一个问题便是AJAX的cache,显然每次载入的脚本和CSS都需要重新传输并不是一件明智的事情。
浏览器对于文件的cache的依据是浏览器的设定(是否每次都下载等),文件的expire头以及用户的操作(刷新)。浏览器cache的文件是根据请求的URL来作为一个key的,也就是说style.css?time=1234567890和style.css?time=1234567891 是两个不同的文件。所以你的脚本和CSS如果没有频繁改动的话,这个时间戳其实并不需要。
总的来说,这是一个很小很小的技巧,对于众多的开发人员来说,甚至不用去加以关心它的实质,框架会帮你做掉这些事情。
添加新评论