发布时间:2019-12-17 分类: 行业资讯
前言
在当今的Internet应用程序中,Web开发中经常遇到性能问题,尤其是当今的Web 2.0+应用程序。 JavaScript是当今使用最广泛的Web开发语言。 Web应用程序的许多性能问题是由程序员编写的JavaScript脚本性能不佳引起的,包括JavaScript语言本身的性能问题及其与DOM的交互。性能问题。本文重点介绍如何尽可能多地避免这些问题,以最大限度地提高Web应用程序的性能。
1.JavaScript性能调优
由于其双线程和解释执行功能,JavaScript语言确定它在许多地方存在性能问题,因此有许多方面需要改进。
1.1评估问题:
比较以下代码:
清单1. eval的问题
带有'eval'的代码比没有'eval'的代码慢100倍。
主要原因是JavaScript代码在执行之前将执行类似'precompilation'的操作:首先在当前执行环境中创建一个活动对象,并将那些用var声明的变量设置为活动对象的属性,但此时变量的赋值是未定义的,函数定义的函数也作为活动对象的属性添加,它们的值正是函数的定义。但是,如果使用'eval','eval'(实际上是字符串)中的代码无法预先识别其上下文,也无法提前解析和优化,即无法进行预编译。因此,它的性能将大大降低。
1.2功能的使用
比较以下代码:
清单2.函数的用法
这与前面提到的'eval'方法类似,其中'func1'的效率远低于'func2',因此推荐使用第二种方法。
1.3函数的范围(范围链)
JavaScript代码解释执行。进入该功能时,它会预先分析当前变量并将它们分配到不同的级别。一般来说:
局部变量放在1级(轻)中,全局变量放在2级(深层)。如果您输入'with'或'try–捕获'代码块,将添加一个新级别,将变量放入“with”或“catch”到最浅层(第1层)并加深之前的级别。 。
请参阅以下代码:
清单3.函数作用域链
在这里我们可以看到'images','widget','combination'属于局部变量,在第1层''document','myObj'属于全局变量,在第2层。
变量所在的层越浅,访问(读取或修改)速度越快,层越深,访问速度越慢。所以这里的'images','widget','组合'访问速度比'document','myObj'快。因此,建议尽可能使用局部变量,请参阅以下代码:
清单4.使用局部变量
我们用局部变量'doc'替换了全局变量'document',这提高了性能,特别是对于广泛使用全局变量的函数。
请查看以下代码:
清单5.谨慎使用
使用'with'关键字,我们可以使代码更简洁明了,但性能会受到影响。正如我之前所说,当我们进入'with'代码块时,'组合'从原始的第1层变为第2层,因此效率大大降低。所以比较一下,仍然使用原始代码:
清单6.使用
进行改进但这不是最好的方法。 JavaScript有一个功能。对于对象对象,属性访问级别越深,效率越低。例如,'myObj'在这里可以访问第3层,我们可以像这样改进它:
清单7.缩小对象访问级别
我们用局部变量替换'myObj'第2层的'container'对象。如果您对对象的深层属性有大量此类访问权限,则可以参考上述内容来提高性能。
1.4字符串(字符串)相关
字符串拼接
我经常看到这段代码:
清单8.简单拼接字符串
Str +='str1'+'str2'
这是我们拼接字符串的常用方法,但这样会创建和销毁一些临时变量,从而影响性能,因此建议使用以下方式:
清单9.字符串数组拼接
Var str_array=[];
Str_array.push( 'STR1');
Str_array.push( 'STR2');
Str=str_array.join('');
这里我们使用数组的'join'方法来实现字符串连接,特别是在旧版本的Internet Explorer(IE6)上运行时,会有显着的性能提升。
当然,最新的浏览器(如Firefox Firefox 3 +,IE8 +等)优化字符串连接,我们也可以写:
清单10.字符串拼接
Str +='str1'
Str +='str2'
新浏览器针对'+='进行了优化,并且执行速度略快于数组的'join'方法。在不久的将来更新版本浏览器也可以优化'+',所以那时我们可以直接写:str +='str1'+'str2'。
隐式类型转换
请参阅以下代码:
清单11.隐式类型转换
这里我们在每个循环中调用字符串'charAt',但由于我们将常量'12345678'赋值给'str','str'实际上不是一个字符串对象,每次调用'charAt'函数时,它暂时构造一个值为'12345678'的字符串对象,然后调用'charAt'方法,最后释放字符串临时对象。我们可以做一些改进:
清单12.避免隐式类型转换
这样,作为字符串对象的变量'str'将不具有这种隐式类型转换过程,并且效率将显着提高。
字符串匹配
JavaScript有一个RegExp对象,支持对字符串进行正则表达式匹配。这是一个很棒的工具,但它的性能不是很好。相反,字符串对象(String)的一些基本方法非常有效,例如'substring','indexOf','charAt'等,当我们需要将字符串与正则表达式匹配时,你可以考虑:
1)问题是否可以通过字符串对象本身支持的基本方法来解决。
2)是否可以缩小'substring'所需的正则表达式的范围。
这些方法可以有效地提高程序的效率。
对于正则表达式对象,还有一点需要注意,请参考以下代码:
清单13.正则表达式
在这里,我们将'/^ s * extras /'传递给'match'方法,这会影响效率。它将构建一个临时值为'/^ s * extras /'的正则表达式对象,并执行'match'方法。然后销毁临时正则表达式对象。我们可以这样做:
清单14.使用变量
这不会有临时对象。
setTimeout和setInterval
两个函数'setTimeout'和'setInterval'可以接受字符串变量,但会带来类似于前面提到的'eval'的性能问题,所以建议直接传递函数对象本身。
使用提前退出
请参阅以下两段代码:
清单15.利用提前退出
代码2对'name.indexOf(…)'有更多的判断,它使程序在每次进入本节时执行'indexOf'判断,然后以'indexOf'比率执行以下'匹配' 。在“匹配”效率更高的前提下,这样做会减少“匹配”的执行次数,从而在一定程度上提高效率。
2. DOM操作性能调优
JavaScript的开发与DOM的操作密不可分,因此DOM操作的性能调优在Web开发中也非常重要。
2.1重绘和回流
重绘也称为重绘,它指的是不影响当前DOM的结构和布局的重绘动作。以下操作将生成重绘操作:
可见(可见性样式属性)
颜色或图像更改(背景,边框颜色,颜色样式属性)
不会更改页面元素的大小,形状和位置,但会更改其外观更改
回流是一个比重绘更重要的变化。它主要发生在操作DOM树时,对DOM结构和布局的任何更改都会产生Reflow。但是,当元素的Reflow操作发生时,它的所有父元素和子元素都将被重排,最后Reflow将不可避免地导致重绘。例如,以下操作将生成重绘操作:
浏览器窗口更改
添加和删除DOM节点的操作
一些触发器可以改变页面元素的大小,形状和位置
2.2减少回流
根据Reflow和Repaint的介绍,每次Reflow带来的资源消耗都比Repaint多,我们应该尝试减少Reflow的发生,或者将其转换为仅触发Repaint操作的代码。
请参阅以下代码:
清单16.重排简介
这是我们经常联系的代码,但是这段代码会产生3次回流。请查看以下代码:
清单17.减少重排
这里只有一个reflow,所以我们推荐这个DOM节点的运行方式。
对于上述解决方案,还有一些模式可以参考,以减少回流操作:
清单18.使用display来减少reflow
首先隐藏pDiv,然后显示它,以便隐藏和显示之间的操作不会产生任何Reflow,从而提高效率。
2.3特殊测量属性和方法
DOM元素中有一些特殊的测量属性访问和方法调用,它们也会触发Reflow,它通常是'offsetWidth'属性和'getComputedStyle'方法。
图1.特殊测量属性和方法
这些测量属性和方法大致如下:
· offsetLeft
·的offsetTop
·的offsetHeight
· offsetWidth
· scrollTop的/左/宽度/高度
· clientTop /左/宽度/高度
·的getComputedStyle()
· currentStyle(在IE中))
访问和调用这些属性和方法将触发Reflow的生成。我们应该最小化这些属性和方法的访问和调用,请参考以下代码:
清单19.特殊测量属性
在这里,我们可以使用临时变量缓存'offsetWidth'的值,这样我们就不必每次都访问'offsetWidth'属性。这种方法在循环中运行良好,可以大大提高性能。
2.4风格相关
我们肯定会看到以下代码:
清单20.与样式相关的
但是你可以看到这里的每个样式更改都会产生Reflow。我们需要减少这种情况,我们可以这样做:
解决方案1:
清单21. className解决方案
通过将class替换为样式,可以将所有先前的Reflow或Repaint的数量减少为1。
解决方案2:
清单22. cssText解决方案
一次设置所有样式也是降低Reflow性能的一种方法。
2.5 XPath
页面通常包含超过1000个页面元素,并且通常需要一定的时间来定位特定元素。如果您使用id或name来定位它可能不会太慢,如果您使用该元素的某些其他属性(例如className等)进行定位,则可能效率较低。有些人可能只能通过遍历所有元素(getElementsByTagName)然后过滤它们来找到所有元素。这甚至更低效。在这里,我们建议使用XPath来查找元素,这是许多浏览器支持的功能。
清单23. XPath解决方案
Browser XPath的搜索引擎可以优化搜索效率并大大缩短结果的返回时间。
2.6 HTMLCollection对象
这是一种特殊的对象,它们有点像数组,但不完全是数组。以下方法的返回值通常是HTMLCollection对象:
· document.images,document.forms
·的getElementsByTagName()
· getElementsByClassName方法()
这些HTMLCollection对象不是固定值,而是动态结果。它们是一些特殊查询的返回值。在下列情况下,它们将重新执行上一个查询以获取新的返回值(查询结果),尽管在大多数情况下它将与前一个或多个返回值相同。 :
·长度属性
·特定成员
因此,HTMLCollection对象对这些属性和成员的访问速度比数组慢得多。当然也有例外。 Opera和Safari可以很好地处理这种情况,并且没有太多的性能问题。
请参阅以下代码:
清单24. HTMLConnection对象
代码的上面两端,下面的效率比上面的段慢得多,因为每个循环都会有一个'items.length'触发器,这将导致'document.getElementsByTagName(..)'方法被再次调用,这就是为什么效率会急剧下降的原因。我们可以这样解决:
清单25. HTMLConnection对象解决方案
这样,效率基本上与普通阵列相同。
2.7动态创建脚本标记
加载和执行JavaScript脚本需要时间。在我们的程序中,有时一些JavaScript脚本在加载后基本上不使用(例如,脚本中的函数从不被调用,等等)。加载这些脚本只会占用CPU时间并增加内存消耗,从而降低Web应用程序的性能。因此,建议动态加载JavaScript脚本文件,尤其是那些内容更多且消耗更多资源的脚本文件。
清单26.创建脚本标记
写在最后
本文介绍了有关Web开发性能的一些小细节。从JavaScript本身开始,我介绍了JavaScript中需要避免的一些函数的使用和编程规则,例如eval的缺点,函数作用域链和String的用法。等等,还共享了一些推荐的实践,并扩展到JavaScript以调整DOM操作的性能调优,例如使用Repaint和Reflow机制,如何使用特殊测量属性,与样式相关的性能调整以及HTMLCollection对象的原理。使用提示。在开发过程中,可以尽可能多地采用这些小细节,以最大限度地提高Web应用程序的性能。