你所在的位置:首 页 >> 代码解读 >> 详细新闻页面


JavaScript优化

作者:zhirong1230 创建时间:2014-05-20 阅读次数:1356


 

        提到Web前端性能优化,那么肯定少不了JavaScript的优化。在讲Web性能优化的时候,很多优化点都是有

利有弊,好坏参半的,很多情况都 要开发者酌情考虑。然后,在JavaScript优化中,大多数就是开发者应该使用和不应该使用的0、1问题,在我的经验中,只要记住哪些不应该用,哪些 优先使用就好。这其实是由于JavaScript这个语言特性所决定的,每个语言都有自己的特性和优点以及缺陷,而JavaScript还
有一些是设计的 很糟糕的东西,开发者应当尽量避免使用。这里推荐一本书《JavaScript语言精粹》,书很短,但可以旋转哦!!
这里,我所说的所有优化点都是简单基础的东西,很多都是借鉴前人的言传身教以及自己的实践经验。没有高大上,没有太过深层次的东西,但即使作为一个屌丝,屌丝的本分还是要做好的。下面主要从三个方面来将JS的优化。
JS文件相关优化
1. 将JS文件作为外部文件引入
    这里web优化中有详细提到,这里再提是为了归类到JS优化中。将静态文件作为外部资源,有效利用

浏览器缓存,除特殊情况,一般都会这么做。
2. JS文件引用放在页面底部
    JS的加载会阻塞浏览器对其他所有资源的获取,即使是现代的高端浏览器做了优化,但还是会阻塞浏

览器的渲染行为,可能导致页面的初始空白。因此尽可能将JS文件放在页面底部。
    这里多说一句,有可能有人还会问,老说页面底部,到底是哪个底部?也许是我多虑,这是个愚蠢的

问题,但我确实有看到,有人将script标签写 在</body>后面,甚至</html>后面,并且跟我说“浏览器

也没报错正常运行啊”。好吧,那是浏览器智能了,但根据 W3C标准,script标签应当出现在head和body

标签中,因此这里说的底部就是</body>之前。
3. 合并JS文件
    将零碎的JS文件进行合并,减小页面加载JS的http请求次数,更好的应当还要根据用途合理分类,使

得项目容易管理。
4. 压缩JS文件
    混淆,去注释。在正式环境中,这是大幅度减小流量的简单使用途径。
5. 动态加载JS文件
    现在的用户越来月难伺候,而页面功能也越来越复杂。用户在期待网站有高端的功能、华丽的特效的

同时,又不愿意多等哪怕多1秒的时间。因此,开发人员不得不考虑动态的加载资源。这里我主要考虑两

个方面。
    延时加载:就是我们常说的LazyLoad。留给我们展示出页面的时间很短,当一个页面的资源太多的时

候,不得不考虑延时加载后续才会使用到的资源,减轻首屏的负担;
    按需加载:现在的页面会有很多的类似“插件”的功能,用户都不希望跳转页面,导致一个页面的功

能点非常多。比如一个隐藏在左下角的播放器,用户点开后可以 播放音乐。比如标签页面,用户可以切

换到别的标签页。在这种情况下,最好考虑按需加载,这里我不去计较什么用户行为学的东西,简单来看

,用户并不一定会去 点看,并不一定会需要的功能,可以先不加载。等到用户实际需要的时候才加载。

当然,这里可能会导致用户后面操作的流畅性。但我们可以根据其重要程度区别对 待啊。
DOM相关优化
1. 优化DOM的访问
    JS在前端中承担了与用户交互中的数据中转与处理的任务,最终总是要访问DOM,给用户反馈的。涉

及到DOM的操作都应当小心慎重,你要付出的代价可能很昂贵,不是在吓你。就算你有台高端的电脑和牛

×的浏览器,挥霍的起,但勤俭节约是中华民族的优良传统啊。
    (1) 减少DOM节点的查询次数,缓存节点。一次DOM查询可能就是一次完整的DOM树遍历啊。将需要多

次访问的节点缓存下来,用内存换时间。
    (2) “线下”处理数据,一次更新DOM。如果需要对DOM的结构做频繁修改计算,尽可不要在DOM上改

来改去,而应当将最后的结果计算出来,然后一次性修改到DOM上。示例:
var i, c = 1000,
m = document.getElementById('test');
m.innerHTML = "";
var d1 = new Date();
for(i = 0; i < c; i++) {
m.innerHTML += i; 
}
var d2 = new Date();
alert("第一次耗时" + (d2.getTime() - d1.getTime()) + "");
 

 

// --------------------------------
m.innerHTML = "";
var d3 = new Date();
var s = "";
for(i = 0; i < c; i++) {
s += i; 
}
m.innerHTML += s; 
var d4 = new Date();
alert("第二次耗时" + (d4.getTime() - d3.getTime()) + "");
    (3) 使用createDocumentFragment()批量修改节点。这里很多文章都有提到,就是所谓的批量修改节

点,但我在测试的时候(连续创建n个文本节点,然后追加到body上的测试),并没有发现有性能提升。

这 里的疑问,如果谁能拍个板子下定论,还望指教。不论是否是由于现代浏览器的优化还是其他原因,

出发点还是好的。想象一下两种处理,在写任何图形界面程序的 时候,是在UI上改来改去好,还是后台

改好所有数据,然后完毕后一次性展示到UI上好呢?也因此,这里还有人提到一种方式,就是先将需要改

动的块整个隐藏 或从DOM树暂时移除,等修改完成后再显示及还原。
    (4) 避免触发强制layout。这一点跟浏览器渲染有关,在接下来讨论浏览器渲染优化的时候在重点讲

。放在这里是因为优化还得从JS写法上改进。
2. 利用事件的冒泡机制,减少事件的绑定
    如果你的web有这样一种情况,你需要对一系列兄弟节点的同一个事件做监听,不妨在其父节点上监

听事件。比如,菜单栏的点击响应这种情况的处理。
    这里需要注意,事件委派可以减少初始化的时间,而且更省事,当子节点动态添加删除时,无需再给

修改的节点绑定事件。但冒泡是会损耗性能为代价的,因为在父 节点上必须得做检查判断,毕竟可能事

件源并不是你所关注的那些节点。如果是鼠标移动这种动不动触发成百上千次的事件,还得慎重考虑,检

查的代价可能很昂 贵。
JS语言特性相关优化
1. 避免使用document.write
    该方法只能在页面加载时使用,否则将重写整个页面。使用这种方式注入标签内容等,会降低web加

载速度,肯定有代替方案。
2. 避免使用位运算
    在JavaScript中没有整型,数字都是双精度的浮点数。Java的位运算由于使用硬件加速,计算非常快

。而JS中不但不是硬件处理,进行位运算还得先将数字转为整数,计算完成后再转回去,执行相当慢。
3. 使用JSON格式创建对象和数组
    直接使用{}, []来定义对象和数组比用new Object、new Array更快。
var obj = {};
var arr = [];
var obj = new Object();
var arr = new Array();
     额外的,使用new Array的方式定义数组,其参数的使用很复杂,很容易出错。
new Array(3, 4, 5); // 结果: [3, 4, 5] 
new Array(3) // 结果: [],此数组长度为 3
     初始化指定长度的数组,仅设置了数组的length属性,数组并没有被定义。
var arr = new Array(3);
arr[1]; // undefined
1 in arr; // false, 数组还没有生成
4. 使用数组join实现字符串连接
    大量碎片文本需要串联时,推荐使用数组的join方法。先将字符串挨个push到数组中,最后join。这

种方法处理大量字符串的连接非常高效。
5. 避免对象嵌套查询
    类似obj1.obj2.obj3.obj4访问时需要3次查询,如果需要多次访问该对象时先缓存对象(例:var 

tmp = obj1.obj2.obj3.obj4,接下来直接使用tmp)。
6. 避免使用eval
    这可以说是javascript的最糟糕设计之一了。使用eval不仅性能低,可读性差,而且很容易导致安全

问题。绝大多数情况使用eval的地方都有别的替代方案。eval的另一个变体是Function()的方式来定义方

法。
eval("myValue = myObject." + myKey + ";"); // 非常糟糕的写法
myValue = myObject[myKey]; // nice
 
7. 避免使用字符串作为setTimeout、setInterval的第一个参数
    该条其实就是上一条,应为这两个方法的第一个参数如果是字符串类型,则会像eval那样去处理。
8. 作用域链优化
    作用域链是JavaScript的一个语言特性,它定义了JS以何种方式去访问方法和属性。不了解的同学可

以去补一下js的作用域链知识。这里需要注意以下几点:
    (1) 少用全局变量。全局变量在作用域链的末端,查询最费时,而且太多全局变量会造成域名污染,

不适合合作开发。
    (2) 避免使用with。这个都不想多谈,完全不要以为这是个什么高大上的东西,请当js没有这个用法

就行。(刚开始学js的时候,我还以为是啥高级用法咧)
    (3) 局部变量缓存处于作用域链末端的(全局)、需要多次访问的变量。局部变量在作用域链的最前

端。
    (4) 循环判断条件使用局部变量。常见情况,判断i是否小于数组长度等。
9. 避免使用for-in遍历
    for-in要迭代搜索实例或者原形的属性,因此比其它三种语法(for、while、do-while)慢很多。如

果是对数组遍历,一定不要用for-in。如果非要用for-in,请记得带上好基友hasOwnProperty。
// 修改 Object.prototype
Object.prototype.bar = 1;

var foo = {moo: 2};
for(var i in foo) {
    console.log(i); // 输出两个属性:bar 和 moo
}

// 通过hasOwnProperty过滤
for(var i in foo) {
    if (foo.hasOwnProperty(i)) {
        console.log(i);
    }
}
 
参考资料:
《javascript语言精粹》
http://bonsaiden.github.io/JavaScript-Garden/zh/


    关键词(keywords):JavaScript优化

分享到: 更多


前一篇: 浅谈网站seo入门心得体会            后一篇:Win8操作系统无缘政府采购 微软称“非常意外”

phpchina   php爱好者   php100    中国网管联盟   LAMP兄弟连   河北联合大学   胜芳趣团网   rss 联系我们 问题反馈
版权所有@:ABCMS新闻发布系统!
建议使用ie6、ie8和 ff 浏览器进行浏览 | 建议分辨率:1024x768
地址:唐山市路北区高新技术产业园区龙华道128号 | 邮编:63000| 邮箱:zhirong1230@yeah.net