问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

简单总结了10个JavaScript代码优化小tips

发布网友 发布时间:2024-10-01 13:32

我来回答

1个回答

热心网友 时间:2024-11-08 22:51

Hi~,我是一碗周,如果写的文章有幸可以得到你的青睐,万分有幸~

?写在前面

想要做到JavaScript的代码优化,首先需要做的是准确的测试JavaScript的代码执行时间。其实需要做的就是采集大量的执行样本进行数学统计和分析,这里我们使用的是benchmark.js来检测代码的执行情况。

首先我们需要在项目中安装依赖,代码如下:

yarnaddbenchmark--save#或者npmibenchmark--save

然后我们写一个测试代码,如下所示:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})

代码执行结果如下:

//join1000x146,854ops/sec±1.86%(88runssampled)//join10000x16,083ops/sec±1.06%(92runssampled)//最快的是:join1000

在结果中,ops/sec表示的是每秒执行的次数,当然是越大越好,紧接着是每秒执行次数上下相差的百分比,最后括号中的内容表示共取样多少次。

或者也可以使用JSBench.me工具进行替换,网站测试截图如下:

我们可以看到,都是join1000的性能更好一些(我感觉我在说废话)。

?慎用全局变量

这里所说的慎用全局变量,为什么要慎用呢?主要有以下几点:

全局变量定义在全局执行上下文,是所有作用域链的顶端。每次查找的时候都从局部找到最顶端,在时间上会有所消耗。

全局执行上下文一直存在于上下文的执行栈,直到程序退出,才会被销毁,内存空间浪费。

如果某个局部作用域出现了同名的变量则会遮盖或者说污染全局变量。

下面我们就来写一段代码,看一下全局变量与布局变量在执行效率方面的差异,代码如下:

...suite.add('全局变量',()=>{//该函数内模拟全局作用域leti,str=''for(i=0;i<1000;i++){str+=i}}).add('局部变量',()=>{for(leti=0,str='';i<1000;i++){str+=i}})...

代码运行结果如下:

全局变量x158,697ops/sec±1.05%(87runssampled)局部变量x160,697ops/sec±1.03%(90runssampled)最快的是:局部变量

虽然说差异不大,但是我们可以感知全局变量比局部的性能更差一些。

?通过原型新增方法

为构造函数增加实例对象需要的方法时,尽量使用原型的方式添加,而不是构造函数内部进行添加,我们可以看如下测试代码:

...suite.add('构造函数内部添加',()=>{functionPerson(){this.sayMe=function(){return'一碗周'}}letp=newPerson()}).add('原型方式内部添加',()=>{functionPerson(){}Person.prototype.sayMe=function(){return'一碗周'}letp=newPerson()})...

代码运行结果如下:

构造函数内部添加x573,786ops/sec±1.97%(89runssampled)原型方式内部添加x581,693ops/sec±3.46%(80runssampled)最快的是:构造函数内部添加?避免闭包中的内存泄露

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,严重可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除(即将局部变量重新赋值为null)。

?避免使用属性访问方法

在JavaScript中的对象中,避免使用一些属性访问方法,这是因为JavaScript中的所有属性都是外部可见的。

示例代码如下:

...suite.add('使用属性访问方法',()=>{functionPerson(){this.name='一碗周'this.getName=function(){return'一碗周'}}letp=newPerson()letn=p.getName()}).add('不使用属性访问方法',()=>{functionPerson(){this.name='一碗周'}letp=newPerson()letn=p.name})...

代码运行结果如下:

使用属性访问方法x406,682ops/sec±2.33%(82runssampled)不使用属性访问方法x554,169ops/sec±2.03%(85runssampled)最快的是:不使用属性访问方法?for循环优化

我们在使用for循环时,可以将有些必要的数据进行缓存,就比如arr.length这种属性,不需要每次判断都获取一下,从而优化我们的代码。

示例代码如下:

...suite.add('正序',()=>{letarr=newArray(100)letstr=''for(leti=0;i<arr.length;i++){str+=i}}).add('缓存',()=>{letarr=newArray(100)letstr=''for(leti=arr.length;i;i--){str+=i}}).add('缓存的另一种写法',()=>{letarr=newArray(100)letstr=''for(leti=0,l=arr.length;i<l;i++){str+=i}})...

代码运行结果如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})0?选择最优的循环方式

我们现在常用的循环有forEach、for和for...in循环,这几种那个是性能最优的呢,测试代码如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})1

代码运行结果如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})2

由运行结果可以看出我们可以尽量使用for...in或者forEach循环,减少使用for循环。

?减少判断层级

减少判断层级就是减少一些if语句的嵌套,如果是一些必要的条件我们可以通过单层if结合return直接跳出函数的执行,关于优化前与优化后的代码执行比对如下所示:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})3

代码运行结果如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})4

虽然说差距并不是很大,但是不适用嵌套的代码比普通代码更优一些。

?减少作用域链查找层级

减少代码中作用域链的查找也是代码优化的一种方法,如下代码展示了两者的区别:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})5

代码运行结果如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})6

上面代码只是为了展示区别,并没有实际意义。

?减少数据读取次数

如果对象中的某个数据在一个代码块中使用两遍以上,这样的话将其进行缓存从而减少数据的读取次数来达到更优的一个性能,测试代码如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})7

代码运行结果如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})8?字面量与构造式

凡是可以使用字面量方式声明的内容,绝对是不可以使用构造函数的方式声明的,两者在性能方面相差甚远,代码如下:

constBenchmark=require('benchmark')constsuite=newBenchmark.Suite()//添加测试suite/***add()方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数*/.add('join1000',()=>{newArray(1000).join('')}).add('join10000',()=>{newArray(10000).join('')})//添加时间监听.on('cycle',event=>{//打印执行时间console.log(String(event.target))})//完成后执行触发的事件.on('complete',()=>{console.log('最快的是:'+suite.filter('fastest').map('name'))})//执行测试.run({async:true})9

代码运行结果如下:

//join1000x146,854ops/sec±1.86%(88runssampled)//join10000x16,083ops/sec±1.06%(92runssampled)//最快的是:join10000?写在最后

本篇文章总结了JavaScript中10个优化代码的小tips,如果对你有所帮助可以点赞支持一下~

原文:https://juejin.cn/post/7113091251708100644
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
不想要淘宝原来的帐号,怎么办,可以注销吗~谢谢了,大神帮忙啊 蓝宝石HD6770显卡求鉴定,GPUZ检测数据如下: 健身60公斤,176身高的人,比较瘦,是不是即便经常锻炼,力气也不一定比胳膊... 农村土地什么情况不予发证?如何解决? 共工治水在前还是怒触不周山在前? 共工触山的故事 有什么类似漂流瓶的软件推荐 漂流瓶软件推荐 保险柜密码怎么改 保险柜密码正确但是打不开怎么办 西安水多少钱一顿 西安哪里可以买自来水 ...现在不能转屏了呢?我昨天晚上完了一下TEMPLE RUN之后,ipad就抽风了... 2021年肥西拆迁过渡费为啥只发一半 帮忙看下这个程序运行为什么会有问题?谢谢 开网店要投资多少钱?要多少成本? esprit的tumble balls是干什么用的 新手开淘宝网店需要多少钱? ...以通过产品设计来推动经济的发展的表现是什么? 衣服口袋里有一个小袋子 上面写着tumble ball 是什么意思 电子琴入门教程内容简介 我为什么不喜欢被人控制 为什么有的人讨厌别人的控制,自己却也一样喜欢控制别人? k5pro啥意思 槐花茶的功效与作用 喝槐花茶的好处有哪些 槐花茶的功效与作用喝槐花茶的好处有哪些 联想K5 Pro:千元影霸究竟有何过人之处? 主板修后用路由器不能上网,192.168.1.1打不开 联想K5 Pro有双扬声器吗? 怎样在手机快手上签到? 192.1.1怎么进? iPhone6位于卡槽那一块小屏幕边缘嗯着响的 其它地方都不响 求解 怎么... 苹果手机云盘怎么使用储存应用 想知道这是什么树和果实。 酷睿U1300怎么样 qq邮箱发送多人邮件时,添加的联系人能不能只留网名而不显示备注... U1300 1.06G处理器怎么样 英特尔酷睿U1300和凌动N270哪个CPU性能强? QQ好友中,我想在QQ面板中只显示好友我修改后的备注姓名,不显示他们的... 酷睿单核 U1300 qq屏蔽人对方知道吗 iphone4里的QQ突然变得不显示备注名只显示网名了,求解决办法 酷睿U1300 1.06G[二级缓存2M] 内存1G硬盘60G 酷睿U1300的主频1.06那么低,性能好吗,有奔腾的2.4,2.66 或3.06的好吗... 酷睿双核L2400 1.66G和酷睿U1300 1.06G[用起来区别有多大 u1300的CPU性能相当于奔腾的哪个级别? 如何自制冰袋,科学冰敷? 想了解下手机如何查询银行卡余额 Bilibili 22卡如何申请? 梦到洪水把家冲没了,但是没看到水,只知道是发大水才让人们无家可归的... bilibili22卡怎么激活 快手上的视频谁能举报?