第一部分:关于script
-
当把js脚本通过script标签放在head中的时候,早期浏览器在遇到script的时候会阻止浏览器加载和渲染html。知道javascript脚本被下载并执行完,且这些javascript是依次下载和执行,不能并行。如下面这个图所示:
现代浏览器如IE8,Firefox 3.5,Safari 4,Chrome 允许同时并行下载js文件。但是不幸的是js下载仍然会阻塞其他资源的下载,如图片。还是会阻止浏览器去加载和渲染html。解决办法就是将js body的最底端。
-
限制script标签的数量,因为每次遇到script都要阻塞浏览器加载和渲染html。这个对于内联和外联js都是一样的。但是对于外联js,每个http请求都需要和服务器建立一次连接,时间上的开销也不小。所以下载一个100KB的js文件比下载4个25KB的js文件速度要快。所以可以将js文件进行文件的合并减少http请求的数量提高性能。
-
非阻塞脚本在html加载完成后进行javascript源码的下载。有几种方法可以做到:
3.1 在script上添加defer属性。defer属性告诉浏览器该javascript代码不会影响dom树。所以浏览器可以放心的将他延迟执行,即等dom加载完成后执行。defer属性的script可以防止浏览器的任何一个地方,当浏览器遇到这个script时候,开始下载但是并不立即执行,等到dom树加载完成在onload事件触发之前执行,且不会影响到其他资源的下载。
<html> <head> <title>Script Defer Example</title> </head> <body> <script defer> alert("defer"); </script> <script> alert("script"); </script> <script> window.onload = function(){ alert("load"); }; </script> </body> </html>
执行结果:
在不支持defer属性的浏览器中结果为:defer script load 在支持defer属性的浏览器中的结果是script defer load
3.2 动态执行将javascript代码插入文档中。
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); }
3.3 通过XHR 从服务端获取js 动态插入到文档中。
第二部分: 关于作用域链和原型链
-
每个函数都会有个作用域链,用于标识符的查找也就是变量的查找。所以如果变量在原型链越后面的地方访问所需要的时间久越长。所以全局对象的返回所需要的时间是最长的,应该用局部变量存起来减少作用域链的查询次数。
-
with语句和try-catch 会改变执行函数的作用域链。会在作用域链前加上with或者catch自己的活跃对象AO。这就导致本来可以自己访问的局部变量需要在作用域链的后面一层被访问到了。增加了变量访问的时间。所以避免使用with语句。而try-catch还是很有用的。不应该避免,可以通过在catch到错误后用一个错误处理函数来解决这种性能问题。
-
在javascript中存储数据的地方又四个。分别是直接量,变量,数组,对象。其中直访问接量和变量是最快的,两者差别不大。但是对于数组和对象相对来说要慢些,特别是对象。因为访问对象中的一些属性和方法涉及到原型链的查找,这个和作用域链是一个道理。所以需要存储这些需要遍历原型链的方法或者属性提供性能。
第三部分 : DOM对象编程
-
浏览器一般分为渲染引擎和js引擎,如chrome 它的渲染引擎就是webkit 它的js引擎是v8。
-
访问和修改dom是需要付出性能代价的。因为修改一个dom元素可能回去触发浏览器去重新计算它的几何属性,重新排版。所以尽可能少的去和dom元素打交道。
-
选用更快的DOM API 比如用nextSibling 代替childNodes 或者用children代替childNodes。