网站建设之脚本加载
网站建设并不是一件简简单单的事情,当然这里说的不会是普通的较小的静态站点。一个网站需要考虑的东西很多,页面整体结构,SEO,css hack, 跨域,脚本加载策略,站点架构,代码压缩等。要成为一名出色的前端开发工程师你除了需要知道上面罗列的这些东西之外还应该具备良好的设计功底,具备后台开发功底。这些都是废话,在这里之谈标题所要表述的内容,那就是脚本加载的问题。脚本在网站开发中可谓是重中之重,在页面交互当中,没有脚本的加入,整个网站也就少了生机。对于javascript这样一个不循规蹈矩的脚本语言来说,我们要想深刻理解它吃透它也是需要一定的时间和开发经验的。
经常,我们会以最普通的标签形式在<head>标签中引入脚本:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <script src="ken.js"></script> 7 </head> 8 <body> 9 10 </body> 11 </html>
1 //ken.js 2 var i = 900000000; 3 while(i > 0) { 4 i--; 5 } 6 console.log('hello');
这样做是在一个大型的网站中是很存在问题的,ken.js这个脚本中执行了比较耗时的操作,所以我们的页面就会渲染的比较慢,对于用户体验而言是相当不好的。
我们有办法能让脚本的加载执行过程由同步变为异步过程,例如加上defer属性,但是该属性在各版本浏览器上并不是十分兼容,也可以用async属性,就像天猫网站上script标签也是用了这样的属性。我们还有好几种异步加载脚本的方式,比如xhr eval技术, xhr注入技术,iframe加载脚本技术等,比较受欢迎的就是document.write这种方式动态加载脚本。
1 var newScript = document.createElement('script');
2 newScript.src = 'ken.js';
3 var script = document.getElementsByTagName('script')[0];
4 script.parentNode.insertBeford(newScript, script);
当然,为了不阻塞页面,我们通常还会将脚本插入位置放在</body>结束标签之前,这里所讲的仅仅是普通的脚本加载技巧。
另外,要想实现在页面全部加载完成后再加载脚本其实也非常简单,相信onload你一定用过,就像下面这样:
1 window.onload = function() { 2 var script = document.createElement('script'); 3 script.src = "ken".js; 4 document.documentElement.firstChild.appendChild(script); 5 };
onload方法就是在页面全部加载完成才会触发的,因此我们只需要在该方法体内动态添加脚本即可,这就是所谓的延迟加载。
有时候我们的页面中会需要加载某些脚本来实现动态效果,但是其中有一些脚本又是多余的,我们在进行模块化开发的时候可以考虑按需加载脚本的方式来进行脚本加载。
按需加载,顾名思义就是根据需要加载必要的脚本,参考requirejs的实现方式为require('a.js', function(a) {});该方式就是当我们加载完成a.js后才去调用回调函数,该形式的实现很简单:
1 function require(file, callback) { 2 var script = document.getElementsByTagName('script')[0], 3 newjs = document.createElement('script'); 4 newjs.onreadyStateChange = function() { 5 if (newjs.readyState === 'loaded' || newjs.readyState === 'complete') { 6 newjs.onreadyStateChange = null; 7 callback(); 8 } 9 }; 10 newjs.onload = function() {callback();}; 11 newjs.src = file; 12 script.parentNode.insertBeford(newjs, script); 13 }
预加载javascript需要解决一个问题,就是如何仅仅加载脚本而不会去执行和解析脚本。因为预加载的脚本可能是为了后面加载的页面用的,而此时页面还未加载,这时就去执行脚本的话就会出错。
在IE浏览器中可以用灯塔模式来实现预加载:
1 new Image().src = "ken.js";
在其他浏览器中可以用<object>来代替脚本元素即可实现预加载:
1 var obj = document.createElement('object'); 2 obj.data = 'ken.js'; 3 document.body.appendChild(obj);
由此,我们可以创建一个通用的preload()函数并使用初始化时分支模式来处理浏览器差异
1 var preload; 2 if (/*@cc_on!*/false) { 3 preload = function(file) { 4 new Image().src = file; 5 }; 6 } else { 7 preload = function(file) { 8 var obj = document.createElement('object'), 9 body = document.body; 10 obj.width = 0; 11 obj.height = 0; 12 obj.data = file; 13 body.appendChild(obj); 14 }; 15 }
以上几个脚本加载方式在日常前端开发中会起到很大的作用,加速网站内容显示和页面体验是前端开发工程师不断的追求。