Javascript在浏览器性能中,这多是全部开发者比较关注的问题,由于Javascript有阻塞的特征,也就是当Javascript运行的时候,浏览器不会处理其余的任务。可是浏览器不可能只运行一个任务,可是同一时间又只能执行单个任务。javascript
无论Javascript代码是内联的仍是包含在一个外部文件中的,页面的下载和解析就必须等待脚本完成,才能继续向下执行,这样的缘由是由于脚本的执行可能会从新渲染页面UI。咱们典型的脚本函数是这样的。如:css
<html> <head> <title>Script Example</title> </head> <body> <div> <script type="text/javascript"> alert("今天的日期是: " + (new Date()).toDateString()); </script> </div> </body> </html>
当浏览器遇到一个<script>标签时,正如上面的HTML页面那样,没办法知道Javascript是否是在div标签中添加或者删除内容,这样浏览器就中止,运行完当前的脚本,而后再继续执行下面的内容。固然使用外链也是这样的过程,遇到src外链Javascript代码,浏览器也是首先加载这个外部Javascript文件,而后解析运行此Javascript代码,至于何时执行,彻底要下载此文件须要多久的时间。html
一、脚本的位置java
从HTML4开始,明确之处,一个<script>标签能够放在HTML文档的<head>和<body>标签中,固然不只限制是连接一个<script>标签,咱们更多的作法是使用<link>标签加载外部的Javascript文件,固然了,其中也包含css文件。如:git
<html> <head> <script type="text/javascript" src="file1.js"></script> <script type="text/javascript" src="file2.js"></script> <script type="text/javascript" src="file3.js"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div> 这是Javascript文件引入的例子。 </div> </body> </html> 可是这样的写法理论上是没有任何问题的,可是这里就存在了性能和体验的问题。上面的代码加载了3个外部文件,每一个文件在加载的过程当中阻塞了页面的解析,浏览器只有等待它们下载并运行了Javascript代码以后,页面才能继续,这咱们在上面已经提到过了。最致命的问题就是,把Javascript文件放在顶部,在加载Javascript文件比较慢的时候会出现空白页,以致于用户看不到页面,更不要说交互网页,推荐的办法就是,把全部的Javascript文件,包括外链的文件挡在<body>标签底部位置,减小对整个页面加载的影响。这里就不列出例子了。
二、延迟脚本github
这个时候就<script>标签出现了一个属性:defer。一个带有defere属性的<script>标签能够防止在文档的任何位置,对应的Javascript文件将在<script>被解析时启动下载,可是代码不会执行,知道DOM加载完成。当一个带有defer的Javascript文件被下载时,他不会阻塞浏览器的其余处理过程,因此这些文件能够与其余页面的其余资源一块儿并行下载。如:跨域
<html> <head> <title>Script Defer Example</title> </head> <body> <script defer> alert("延迟"); </script> <script> alert("当前"); </script> <script> window.onload = function(){ alert("加载完成") }; </script> </body> </html> ## 标题文字 ##
若是浏览器不支持defer属性,上面的代码的运行顺序是: 延迟-》当前-》加载完成。若是浏览器支持defer属性,那么运行顺序是:当前-》延迟-》加载完成。应该很直观的就能看出区别。目前defer标签目前已被全部主流浏览器支持数组
另外这不能不提的还有一个属性:async。用于加载异步脚本,async和defer的相同点是采用并行下载,在下载的过程当中都是不会产生阻塞。区别在于执行时机,async是加载完成后自动执行,,而defer须要等待页面完成后执行。浏览器
三、动态脚本元素缓存
DOM容许使用Javascript动态建立HTML支持的所有内容。如:
var script = document.createElement ("script"); script.type = "text/javascript"; script.src = "file1.js"; document.getElementsByTagName_r("head")[0].appendChild(script);
上面新的<script>元素file.js源文件,此文件被添加到页面以后马上开始下载。最重要的一点是这部分代码的加载和运行不会阻塞其余页面处理过程。
这里有一个封装方法,能够实现浏览器兼容模式:
function loadScript(url, callback){ var script = document.createElement ("script") script.type = "text/javascript"; if (script.readyState){ //IE script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; callback(); } }; } else { //Others script.onload = function(){ callback(); }; } script.src = url; document.getElementsByTagName_r("head")[0].appendChild(script); }
此方法接受两个参数:url,和一个当Javascript接受完成时触发的回调函数。最后设置src属性,再将<script>元素添加到页面。使用方法为:
loadScript("file1.js", function(){ alert("文件加载完成!"); });
四、XHR脚本注入
还有一个非阻塞方式活的脚本的方法是使用XMLHttpRequest(XHR)对象加载Javascript脚本,原理就是建立一个XHR对象,而后下载Javascript文件,再用一个动态的<script>元素将Javascript代码注入页面。如:
var xhr = new XMLHttpRequest(); xhr.open("get", "file1.js", true); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ 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);
此代码向服务器发送一个获取file.js文件的请求,这个请求是GET模式,onreadystatechange事件处理函数检查readyState是否是4,而后检查HTTP状态码是否是有效的2XX有效的回应,或者是304的缓存相应。若是收到有效相应,那么就建立一个新的<script>元素,而后文本属性设置为从服务接收到的respinseText字符串。这样作实际上会chaungjian一个带有内联代码的<sript>元素。一旦新的<script>元素被添加到文档,代码将会被执行。
这样的好处是,能够下载但不是当即执行Javascript代码,还有一个好处是兼容性好。
缺点就是不能跨域使用。
五、LazyLoad 类库
Yahoo! Search的工程师建立了一个更为通用的LazyLoad库(参见:http://github.com/rgrove/lazy...)LazyLoad是一个更增强大的loadScript()函数,LazyLoad压缩后体积很小,用法:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js("file.js", function(){ Application.init(); }); </script>
LazyLoad也能够同时下载多个Javascript文件,并保证它们在全部浏览器上都能以正确的顺序远行,要加载多个Javascript文件,只须要在执行LazyLoad()函数时传递一个数组便可,如:
<script type="text/javascript" src="lazyload-min.js"></script> <script type="text/javascript"> LazyLoad.js(["file1.js", "file2.js"], function(){ Application.init(); }); </script>
固然还有其余类库,好比 LABjs 这里就不一一介绍了。
总结
将全部的<script>标签放置在页面底部,紧靠body标签的上方,些方法能够保证页面在脚本运行以前完成解析。最好不管Javascript文件是以什么样的方式加载的。
讲脚本打包,尽可能合并页面的Javascript文件,文件越少,页面的加载速度就会越快,不管是内联的仍是外链的Javascript文件。
同步博客地址:http://www.sundexin.com
微博:http://weibo.com/1674378140/p...