浏览器对javascript的处理主要有2部分:下载和执行javascript
下载在有些浏览器中是并行的,有些浏览器中是串行的,如IE八、Firefox三、Chrome2都是串行下载的css
执行在全部浏览器中默认都是阻塞的,当js在执行时不会进行html解析等其它操做html
javascript有个阻塞特性,当浏览器执行javascript代码时,不能同时作其它任何事情。不管当前javascript代码是内嵌仍是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成。浏览器在下载和执行脚本是进出现阻塞的缘由在于,脚本可能会改变页面或javascript的命名空间,它们对后面页面内容形成影响。java
浏览器在碰到一个引入外部javascript文件的<script>标签时会停下全部工做来下载并解析执行它,在这个过程当中,页面渲染和用户交互彻底被阻塞了。例:git
<html> <head> <title>无标题文档</title> <link rel="stylesheet" type="text/css" href="styles.css" /> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> </body> </head> <body> <p>页面的内容。。。</p> </body> </html>
因为脚本的阻塞特性,页面会在3个javascript文件所有下载执行完成后,页面才会继续渲染,把脚本放在页面顶部会致使明显延迟,一般表现为显示空白页,用户没法浏览内容,也没法与页面交互。github
ie8+、firefox 3.5+、safari4+、chrome2+都容许并行下载javascript文件,可是在下载的过程当中仍然会阻塞图片等其它资源的下载。chrome
因为脚本会阻塞页面其它资源的下载,所以推荐将javasrcipt尽可能放到body标签的底部,以减小对整个页面下载的影响。数组
因为<script>标签在下载时会阻塞页面的渲染,因此减小<script>标签数量有助于改善这一状况。建议将多个javascript文件合并为一个,这样能够减小性能的消耗。同时也能够减小请求的数量。浏览器
(参考:在服务端合并和压缩javascript和CSS文件)app
HTML4 为<script>标签订义了一个defer 属性,它能使这段代码延迟执行,然而该属性只有IE4+支持,所以它不是一个理想的跨浏览器解决方案。声明了defer 属性的script会在DOM加载完成,window.onload 事件触发前被解析执行:
<html> <head> <title>script defer example</title> </body> </head> <body> <script defer> alert('defer'); </script> <script> alert('script'); </script> <script> window.onload = function(){ alert('load'); } </script> </body> </html>
这段代码在支持defer属性的浏览器弹出顺序是:script、defer、load;不支持defer属性的浏览器弹出的顺序是defer、script、load。
<script type="text/javascript"> function loadScript(url, callback) { var script = document.createElement('script') script.type = 'text/javascript'; if (script.readyState) { //for ie script.onreadystatechange = function() { if (script.readyState == 'loaded' || script.readyState == 'complete') { script.onreadystatechange = null; callback(); } }; } else { //other browser script.onload = function() { callback(); }; } script.src = url; document.getElementsByTagName('head')[0].appendChild(script); } </script>
loadscript函数用法
<script type="text/javascript"> //单个文件 loadScript('file1.js', function(){ alert('loaded!'); }); //多个文件 loadScript('file1.js', function(){ loadScript('file2.js',function(){ loadScript('file3.js', function(){ alert('all files loaded!'); }); }); }); </script>
这种技术的重点在于:不管什么时候启动下载,文件的下载和执行过程不会阻塞页面其它进程,你甚至能够将代码放在页面的head区域而不影响页面的其它部分(下载该文件的http连接除外)。
此技术会先建立一个XHR对象,而后用它下载javascript文件,最后建立动态的script元素将代码注入到页面中。
<script type="text/javascript"> var xhr = new XMLHttpRequest(); xhr.open('get', 'file1.js', true); xhr.onreadystatechange = function() { if (xhr.status >= 200 && xhr.status <300 || xhr.status == 304) { var script = document.createElement('script'); script.type = 'text/javascript'; script.text = xhr.responseText; document.body.appendChild(script); } }; xhr.send(null); </script>
这种方法优势是能够直接下载javascript代码但不当即执行。因为代码是在<script>标签以外返回的,所以下载后不会自动执行,这使得是能够把脚本推迟到你准备好的时候。这种方法的局限性在于javascript文件必须与所请求的页面处于相同的域,这意味着javascript文件不能从cdn下载,所以不适合大型网站或项目。
Yahoo!Search工程师Ryan Grove建立的一个通用的延迟加载工具,是loadScript()函数的加强版。
用法示例:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js('the-reset.js', function(){ Application.init(); }); </script>
LazyLoad一样支持多个javascript文件,并能保证在全部浏览器中均可以按正确的顺序执行。要加载多个javscript文件,只须要给LazyLoad.js()y方法传入一个url数组:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js(['first.js', 'the-reset.js'], function(){ Application.init(); }); </script>
项目地址:https://github.com/rgrove/lazyload
LABjs是Kyle Simpson受Steve Sounders的启发实现的无阻塞加载工具。用法示例:
<script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script('the-reset.js') .wait(function(){ Application.init(); }); </script>
$LAB.script()方法用来定义须要下载的javascript文件,$LAB.wait()用来指定文件下载并执行完毕后所调用的函数。
要下载多个javscript文件,只需链式调用另外一个$LAB.script()方法:
<script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script('first.js') .script('the-reset.js') .wait(function(){ Application.init(); }); </script>
LABjs不同凡响的是它管理依赖关系的能力。一般来讲,连续的<script>标签意味着文件逐个下载并按顺序执行。
LABjs容许使用wait()方法来指定哪些文件须要等待其它文件。上面的例子中first.js不能保证会在the-reset.js的代码前执行,为了确保这一点,必须在第一个script()方法后调用wait():
<script type="text/javascript" src="lab.js"></script> <script type="text/javascript"> $LAB.script('first.js').wait() .script('the-reset.js') .wait(function(){ Application.init(); }); </script>
项目地址:hhttp://labjs.com/
SeaJS 是淘宝玉伯开发的一个遵循 CommonJS 规范的模块加载框架,可用来轻松愉悦地加载任意 javascript 模块。详细请参考:http://seajs.com/docs/
Do是豆瓣网kejun开发的一个很轻量的Javascript开发框架。目前do.min.js。它的核心功能是对模块进行组织和加载。加载采起并行异步队列的策略,而且能够控制执行时机。Do能够任意置换核心类库,默认是jQuery。
项目地址:https://github.com/kejun/Do