JS性能优化实现方法及优点进行


Posted in Javascript onAugust 30, 2020

最近刚阅读完《高性能javascript》,想谈谈对js性能优化的看法。理解有些不同,可能还需要各位多多提醒。

话不多说,提到javascript难免会联想到文档对象模型(DOM),它作用于XML和HTML文档的程序接口(API),位于浏览器中,主要用来与HTML文档打交道。同样也用于Web程序中获取XML文档,并使用DOM API来访问文档中的数据。尽管DOM是个与语言无关的API,它在浏览器中的接口却是用javascript实现的。客户端脚本编程大多数时候是在和底层文档(underlying document) 打交道,DOM就成为现在javascript编程中的重要部分。

浏览器通常会把DOM和js独立实现。比如在IE中,javascript的实现名为Jscript,位于jscript.dll文件中;DOM的实现则存在另一个库中,名为mshtml.dll(内部称为Trident)。这个分离允许的其他技术和语言,比如VBScript,能共享使用DOM以及Trident提供的渲染函数。Safari中的DOM和渲染使用的Webkit中的WebCode实现,javascript部分是由独立的javascriptCode引擎(最新版本的名字为SquirrelFish)来实现。Google Chrome同样使用WebKit中的WebCore库来渲染页面,但javascript引擎是他们自己研发的,名为V8。Firefox的javascript引擎名为SpiderMonkey(最新版的名字为TraceMonkey),与名为Gecko的渲染引擎相互独立。

把DOM和javascript(这里指ECMAScript,JavaScript使用的ECMAScript版本为ECMAScript-262)各自想象一个岛屿,它们之间用收费桥梁连接。ECMAScript每次访问DOM,都需要途经这座桥,并交纳“过桥费”。访问DOM的次数越多,费用越高。所以想办法减少过桥次数就可以减少费用。

一、超载运输

上面提到“过桥费”很贵啊,那么我们尽量使需要多次去访问DOM的时候全部整合到一次。比如最简单的例子:

function innerHTMLLoop(){
   for(var count = 0;count < 15000 ;count++){
      document.getElementById('here').innerHTML +='a';
  } 
}

这个函数循环修改页面元素的内容。这段代码存在循环迭代,该元素都被访问两次,一次是读取innerHTML属性值,另一次是重写它。(意味着每次循环都必须付“过桥费”)。

为了减少费用,我们采取一种更高效的方法,例:

function innerHTMLLoop2(){
   var content = ' ';
   for(var count = 0;count < 15000 ;count++){
      content +='a';
  } 
  document.getElementById('here').innerHTML +=content;
}

这样只需要付一次“过桥费”,就可以完成相同的功能。运行速度在不同的浏览器中都有大幅度的提升,例如IE6中,使用innerHTMLLoop2()比使用innerHTMLLoop()快155倍。(所以现实当中好多大卡车超载也是为了省这个费用,一次性多赚点。不过还是量力而行。程序也是一样,均衡存乎万物之间。)

二、触手可及

尽管使用优化过的javascript引擎的新型浏览器,对于对象成员引用也存在一些性能问题。对象在原型链中存在的未知越深,找到它也就越慢,例如不太常见的写法:window.location.href。每次遇到点操作符,嵌套成员会导致Javascipt引擎搜索所有对象成员。对象成员嵌套得越深,读取速度就会越慢。执行location.href总是比window.location.href要快,后者也比window.location.href.toString()要快。如果这些属性不是对象的实例属性,那么成员解析还需要搜索原型链,这会花更多的时间。

由于类似的性能问题都是与对象成员有关,因此应该尽可能避免使用它们。更准确地说,应当注意,只在必要时使用对象成员。例如,在同一个函数中没有必要多次读取同一个对象成员。例:

function hasEitherClass(element,className1,className2){
   return element.className == className1 || element.className == className2; 
}

以上的代码,element.className读取了2次。意味着在该函数语句中2次成员查找都是通过读取属性值,那么有必要子啊第一次查找到值后就将其存储在局部变量中,因为局部变量的读取速度要快很多。例:

function hasEitherClass(element,className1,className2){
   var currentClassName = element.className;
   return currentClassName == className1 || currentClassName == className2; 
}

上面element.className 赋值在currentClassName局部变量,避免了多次查找带来的性能开销。(多次需要全局对象成员,那就赋值在最容易拿到的地方,这样可以减少去搜索和查找)

总结

虽然我还有很多要讲,但是太多太多的方式可以进行性能优化,以后有更好的再补充。不过优化就是跟人找方法用最小的力量去做最大的事情一样,说俗点就是“懒”,我们让程序也懒。

下面是一些关于客户端JS性能的一些优化的小技巧:

1.[顶]关于JS的循环,循环是一种常用的流程控制。JS提供了三种循环:for(;;)、while()、for(in)。在这三种循环中 for(in)的效率最差,因为它需要查询Hash键,因此应尽量少用for(in)循环,for(;;)、while()循环的性能基本持平。当然,推 荐使用for循环,如果循环变量递增或递减,不要单独对循环变量赋值,而应该使用嵌套的++或--运算符。

2.如果需要遍历数组,应该先缓存数组长度,将数组长度放入局部变量中,避免多次查询数组长度。

3.局部变量的访问速度要比全局变量的访问速度更快,因为全局变量其实是window对象的成员,而局部变量是放在函数的栈里的。

4.尽量少使用eval,每次使用eval需要消耗大量时间,这时候使用JS所支持的闭包可以实现函数模板。

5.尽量避免对象的嵌套查询,对于obj1.obj2.obj3.obj4这个语句,需要进行至少3次查询操作,先检查obj1中是否包含 obj2,再检查obj2中是否包含obj3,然后检查obj3中是否包含obj4...这不是一个好策略。应该尽量利用局部变量,将obj4以局部变量 保存,从而避免嵌套查询。

6.使运算符时,尽量使用+=,-=、*=、\=等运算符号,而不是直接进行赋值运算。

7.[顶]当需要将数字转换成字符时,采用如下方式:"" + 1。从性能上来看,将数字转换成字符时,有如下公式:("" +) > String() > .toString() > new String()。String()属于内部函数,所以速度很快。而.toString()要查询原型中的函数,所以速度逊色一些,new String()需要重新创建一个字符串对象,速度最慢。

8.[顶]当需要将浮点数转换成整型时,应该使用Math.floor()或者Math.round()。而不是使用parseInt(),该方法用于将字符串转换成数字。而且Math是内部对象,所以Math.floor()其实并没有多少查询方法和调用时间,速度是最快的。

9.尽量作用JSON格式来创建对象,而不是var obj=new Object()方法。因为前者是直接复制,而后者需要调用构造器,因而前者的性能更好。

10.当需要使用数组时,也尽量使用JSON格式的语法,即直接使用如下语法定义数组:[parrm,param,param...],而不是采用 new Array(parrm,param,param...)这种语法。因为使用JSON格式的语法是引擎直接解释的。而后者则需要调用Array的构造器。

11.[顶]对字符串进行循环操作,例如替换、查找,就使用正则表达式。因为JS的循环速度比较慢,而正则表达式的操作是用C写成的API,性能比较好。

最后有一个基本原则,对于大的JS对象,因为创建时时间和空间的开销都比较大,因此应该尽量考虑采用缓存。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ajax 缓存 问题 requestheader
Aug 01 Javascript
20个非常棒的 jQuery 幻灯片插件和教程分享
Aug 23 Javascript
分享28款免费实用的 JQuery 图片和内容滑块插件
Dec 15 Javascript
js实现仿阿里巴巴城市选择框效果实例
Jun 24 Javascript
Javascript技术栈中的四种依赖注入小结
Feb 27 Javascript
jQuery中ztree 点击文本框弹出下拉框的实例代码
Feb 05 Javascript
Angular实现的简单查询天气预报功能示例
Dec 27 Javascript
mint-ui在vue中的使用示例
Apr 05 Javascript
利用Electron简单撸一个Markdown编辑器的方法
Jun 10 Javascript
javascript sort()对数组中的元素进行排序详解
Oct 13 Javascript
微信小程序新闻网站详情页实例代码
Jan 10 Javascript
JS中准确判断变量类型的方法
Jun 01 Javascript
如何检测JavaScript中的死循环示例详解
Aug 30 #Javascript
JavaScript中CreateTextFile函数
Aug 30 #Javascript
详解vue组件之间的通信
Aug 30 #Javascript
如何阻止移动端浏览器点击图片浏览
Aug 29 #Javascript
JavaScript事件委托实现原理及优点进行
Aug 29 #Javascript
JS如何判断对象是否包含某个属性
Aug 29 #Javascript
JS获取当前时间戳方法解析
Aug 29 #Javascript
You might like
html中select语句读取mysql表中内容
2006/10/09 PHP
PHP 加密解密内部算法
2010/04/22 PHP
php自动给文章加关键词链接的函数代码
2012/11/29 PHP
PHP连接MSSQL时nvarchar字段长度被截断为255的解决方法
2014/12/25 PHP
Laravel接收前端ajax传来的数据的实例代码
2017/07/20 PHP
thinkphp3.2.0 setInc方法 源码全面解析
2018/01/29 PHP
再谈javascript 动态添加样式规则 W3C校检
2009/12/25 Javascript
jQuery 前的按键判断代码
2010/03/19 Javascript
为JavaScript添加重载函数的辅助方法
2010/07/04 Javascript
javascript中日期转换成时间戳的小例子
2013/03/21 Javascript
基于pthread_create,readlink,getpid等函数的学习与总结
2013/07/17 Javascript
详解vue移动端项目的适配(以mint-ui为例)
2018/08/17 Javascript
JS/HTML5游戏常用算法之碰撞检测 地图格子算法实例详解
2018/12/12 Javascript
Vue form表单动态添加组件实战案例
2019/09/02 Javascript
js实现计时器秒表功能
2019/12/16 Javascript
js实现简单的随机点名器
2020/09/17 Javascript
小程序实现tab标签页
2020/11/16 Javascript
[01:18:43]2014 DOTA2华西杯精英邀请赛5 24 iG VS DK
2014/05/25 DOTA
python抓取网页时字符集转换问题处理方案分享
2014/06/19 Python
Python使用cx_Freeze库生成msi格式安装文件的方法
2018/07/10 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
2019/02/27 Python
纯CSS3实现给头像加个光芒四射且旋转的背景动画效果
2014/05/07 HTML / CSS
基于html5 canvas做批改作业的小插件
2020/05/20 HTML / CSS
Monnier Freres中文官网:法国领先的奢侈品配饰在线零售商
2017/11/01 全球购物
英国快时尚女装购物网站:PrettyLittleThing
2018/08/15 全球购物
UNIX文件系统常用命令
2012/05/25 面试题
销售工作人员的自我评价分享
2013/11/10 职场文书
迷你西餐厅创业计划书范文
2013/12/31 职场文书
ktv中秋节活动方案
2014/01/30 职场文书
学习优秀党务工作者先进事迹材料思想报告
2014/09/17 职场文书
2014年法院个人工作总结
2014/12/17 职场文书
党员年度个人总结
2015/02/14 职场文书
河童之夏观后感
2015/06/11 职场文书
公务员岗前培训心得体会
2016/01/08 职场文书
送给火锅店的创意营销方案!
2019/07/08 职场文书
MySQL 使用自定义变量进行查询优化
2021/05/14 MySQL