@@ -833,6 +833,68 @@ frist_script是页面中一定存在的一个script标签,script是你创建
833833
834834对很多应用来说,延迟加载的部分大部分情况下会比核心部分要大,因为我们关注的“行为”(比如拖放、XHR、动画)只在用户初始化之后才会发生。
835835
836+ ###按需加载
837+
838+ 前面的模式会在页面加载后无条件加载其它的JavaScript,并假设这些代码很可能会被用到。但我们是否可以做得更好,分部分加载,在真正需要使用的时候才加载那一部分?
839+
840+ 假设你页面的侧边栏上有一些tabs。点击tab会发出一个XHR请求获取内容,然后更新tab的内容,然后有一个更新的动画。如果这是页面上唯一需要XHR和动画库的地方,而用户又不点击tab的话会怎样?
841+
842+ 下面介绍按需加载模式。你可以创建一个require()函数或者方法,它接受一个需要被加载的脚本文件的文件名,还有一个在脚本被加载完毕后执行的回调函数。
843+
844+ require()函数可以被这样使用:
845+
846+ require("extra.js", function () {
847+ functionDefinedInExtraJS();
848+ });
849+
850+ 我们来看一下如何实现这样一个函数。加载脚本很简单——你只需要按照动态\< script\> 元素模式做就可以了。获知脚本已经加载需要一点点技巧,因为浏览器之间有差异:
851+
852+ function require(file, callback) {
853+
854+ var script = document.getElementsByTagName('script')[0], newjs = document.createElement('script');
855+
856+ // IE
857+ newjs.onreadystatechange = function () {
858+ if (newjs.readyState === 'loaded' || newjs.readyState === 'complete') {
859+ newjs.onreadystatechange = null;
860+ callback();
861+ }
862+ };
863+
864+ // others
865+ newjs.onload = function () {
866+ callback();
867+ };
868+
869+ newjs.src = file;
870+ script.parentNode.insertBefore(newjs, script);
871+ }
872+
873+ 这个实现的几点说明:
874+
875+ - 在IE中需要订阅readystatechange事件,然后判断状态是否为“loaded”或者“complete”。其它的浏览器会忽略这里。
876+ - 在Firefox,Safari和Opera中,通过onload属性订阅load事件。
877+ - 这个方法在Safari 2中无效。如果必须要处理这个浏览器,需要设一个定时器,周期性地去检查某个指定的变量(在脚本中定义的)是否有定义。当它变成已定义时,就意味着新的脚本已经被加载并执行。
878+
879+ 你可以通过建立一个人为延迟的脚本来测试这个实现(模拟网络延迟),比如ondemand.js.php,如:
880+
881+ <?php
882+ header('Content-Type: application/javascript');
883+ sleep(1);
884+ ?>
885+ function extraFunction(logthis) {
886+ console.log('loaded and executed');
887+ console.log(logthis);
888+ }
889+
890+ 现在测试require()函数:
891+
892+ require('ondemand.js.php', function () {
893+ extraFunction('loaded from the parent page');
894+ document.body.appendChild(document.createTextNode('done!'));
895+ });
896+
897+ 这段代码会在console中打印两条,然后页面中会显示“done!”,你可以在< http://jspatterns.com/book/7/ondemand.html > 看到示例。
836898
837899
838900