没有找到合适的产品?
联系客服协助选型:023-68661681
提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
翻译|其它|编辑:郝浩|2007-10-23 13:35:05.000|阅读 738 次
概述:
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
除了像 aimingoo 做个案研究外,这里我想从更一般的角度总结在浏览器编程中 JS 优化的几个原则。
首先,与其他语言不同,JS 的效率很大程度是取决于 JS engine 的效率。除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化的策略。例如FF、Opera 和 Safari 的JS引擎,都对字符串的拼接运算(+)做了特别优化。显然,要获得最大效率,就必须要了解引擎的脾气,尽量迎合引擎的口味。所以对于不同的引擎,所作的优化极有可能是背道而驰的。
而如果做跨浏览器的 web 编程,则最大的问题是在于 IE6(JScript 5.6)!因为在不打 hotfix 的情况下,JScript 引擎的垃圾回收的 bug,会导致其在真实应用中的 performance 跟其他浏览器根本不在一个数量级上。因此在这种场合做优化,实际上就是为 JScript 做优化!
所以第一原则就是只需要为 IE6(未打补丁的 JScript 5.6或更早版本)做优化!
如果你的程序已经优化到在 IE6下可以接受的性能,那基本上在其他浏览器上性能就完全没有问题。
因此,注意我下面讲的许多问题在其他引擎上可能完全不同,例如在循环中进行字符串拼接,通常认为需要用 Array.join 的方式,但是由于 SpiderMonkey 等引擎对字符串的“+”运算做了优化,结果使用 Array.join 的效率反而不如直接用“+”!但是如果考虑 IE6,则其他浏览器上的这种效率的差别根本不值一提。
JS 优化与其他语言的优化也仍然有相同之处。比如说,不要一上来就急吼吼的做优化,那样毫无意义。优化的关键,仍然是要把精力放在最关键的地方,也就是瓶颈上。一般来说,瓶颈总是出现在大规模循环的地方。这倒不是说循环本身有性能问题,而是循环会迅速放大可能存在的性能问题。
所以第二原则就是以大规模循环体为最主要优化对象。
以下的优化原则,只在大规模循环中才有意义,在循环体之外做此类优化基本上是没有意义的。
目前绝大多数 JS 引擎都是解释执行的,而解释执行的情况下,在所有操作中,函数调用的效率是较低的。此外,过深的 prototype 继承链或者多级引用也会降低效率。JScript 中,10级引用的开销大体是一次空函数调用开销的1/2。这两者的开销都远远大于简单操作(如四则运算)。
所以第三原则就是尽量避免过多的引用层级和不必要的多次方法调用。
特别要注意的是,有些情况下看似是属性访问,实际上是方法调用。例如所有 DOM 的属性,实际上都是方法。在遍历一个 NodeList 的时候,循环条件对于nodes.length的访问,看似属性读取,实际上是等价于函数调用的。而且IE DOM 的实现上,childNodes.length 每次是要通过内部遍历重新计数的。(My god,但是这是真的!因为我测过,childNodes.length 的访问时间与 childNodes.length 的值成正比!)这非常耗费。所以预先把 nodes.length 保存到 js 变量,当然可以提高遍历的性能。
同样是函数调用,用户自定义函数的效率又远远低于语言内建函数,因为后者是对引擎本地方法的包装,而引擎通常是 c,c++,java 写的。进一步,同样的功能,语言内建构造的开销通常又比内建函数调用要效率高,因为前者在 JS 代码的 parse 阶段就可以确定和优化。
所以第四原则就是尽量使用语言本身的构造和内建函数。
这里有一个例子是高性能的 String.format 方法。String.format 传统的实现方式是用 String.replace(regex, func),在 pattern 包含 n 个占位符(包括重复的)时,自定义函数func就被调用n次。而这个高性能实现中,每次 format 调用所作的只是一次 Array.join 然后一次 String.replace(regex, string)的操作,两者都是引擎内建方法,而不会有任何自定义函数调用。两次内建方法调用和n次的自定义方法调用,这就是性能上的差别。
同样是内建特性,性能上也还是有差别的。例如在 JScript 中对于arguments 的访问性能就很差,几乎赶上一次函数调用了。因此如果一个可变参数的简单函数成为性能瓶颈的时候,可以将其内部做一些改变,不要访问 arguments,而是通过对参数的显式判断来处理。
比如:
代码
function sum() {
var r = 0;
for (var i = 0; i < arguments.length; i++) {
r += arguments[i];
}
return r;
}
这个 sum 通常调用的时候个数是较少的,我们希望改进它在参数较少时的性能。如果改成:
代码
function sum() {
switch (arguments.length) {
case 1: return arguments[0];
case 2: return arguments[0] + arguments[1];
case 3: return arguments[0] + arguments[1] + arguments[2];
case 4: return arguments[0] + arguments[1] + arguments[2] + arguments[3];
default:
var r = 0;
for (var i = 0; i < arguments.length; i++) {
r += arguments[i];
}
return r;
}
}
其实并不会有多少提高,但是如果改成:
代码
function sum(a, b, c, d, e, f, g) {
var r = a ? b ? c ? d ? e ? f ? a + b + c + d + e + f : a + b + c + d + e : a + b + c + d : a + b + c : a + b : a : 0;
if (g === undefined) return r;
for (var i = 6; i < arguments.length; i++) {
r += arguments[i];
}
return r;
}
就会提高很多(至少快1倍)。
最后是第五原则,也往往是真实应用中最重要的性能障碍,那就是尽量减少不必要的对象创建。
本身创建对象是有一定的代价的,但是这个代价其实并不大。最根本的问题是由于 JScript 愚蠢之极的垃圾回收调度算法,导致随着对象个数的增加,性能严重下降(据微软的人自己说复杂度是O(n^2))。
比如我们常见的字符串拼接问题,经过我的测试验证,单纯的多次创建字符串对象其实根本不是性能差的原因。要命的是在对象创建期间的无谓的垃圾回收的开销。而 Array.join 的方式,不会创建中间字符串对象,因此就减少了那该死的垃圾回收的开销。
因此,如果我们能把大规模对象创建转化为单一语句,则其性能会得到极大的提高!例如通过构造代码然后 eval ——实际上 PIES 项目中正在根据这个想法来做一个专门的大规模对象产生器……
好了上面就是偶总结的 JS 优化五大原则。
除了这些原则以外,还有一些特殊情况,如 DOM 的遍历,以后有时间再做讨论。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com
文章转载自:JavaEye面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@evget.com
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢
慧都科技 版权所有 Copyright 2003-
2025 渝ICP备12000582号-13 渝公网安备
50010702500608号