이 글은 javascript에 대한 관련 지식을 제공합니다. 주로 10가지 JavaScript 코드 최적화 팁을 소개하고 요약합니다. 이 글은 주제를 중심으로 내용을 자세히 소개하며 모든 사람에게 도움이 되기를 바랍니다.
【관련 권장사항: javascript 동영상 튜토리얼, web front-end】
JavaScript 코드를 최적화하려면 가장 먼저 해야 할 일은 JavaScript를 정확하게 테스트하는 것입니다. 코드 실행 시간. 실제로 수행해야 할 작업은 수학적 통계 및 분석을 위해 많은 수의 실행 샘플을 수집하는 것입니다. 여기서는 benchmark.js
를 사용하여 코드 실행을 감지합니다. benchmark.js
来检测代码的执行情况。
首先我们需要在项目中安装依赖,代码如下:
yarn add benchmark --save # 或者 npm i benchmark --save
然后我们写一个测试代码,如下所示:
const Benchmark = require('benchmark') const suite = new Benchmark.Suite() // 添加测试 suite /** * add() 方法接受两个参数,其中第一个表示测试的名称,第二个表示测试的内容,他是一个函数* / .add('join1000', () => { new Array(1000).join(' ') }) .add('join10000', () => { new Array(10000).join(' ') }) // 添加时间监听 .on('cycle', event => { // 打印执行时间 console.log(String(event.target)) }) // 完成后执行触发的事件 .on('complete', () => { console.log('最快的是:' + suite.filter('fastest').map('name')) }) // 执行测试 .run({ async: true }) 复制代码
代码执行结果如下:
// join1000 x 146,854 ops/sec ±1.86% (88 runs sampled)
// join10000 x 16,083 ops/sec ±1.06% (92 runs sampled)
// 最快的是:join1000
在结果中,ops/sec
表示的是每秒执行的次数,当然是越大越好,紧接着是每秒执行次数上下相差的百分比,最后括号中的内容表示共取样多少次。我们可以看到,都是join1000
的性能更好一些(我感觉我在说废话)。
这里所说的慎用全局变量,为什么要慎用呢?主要有以下几点:
下面我们就来写一段代码,看一下全局变量与布局变量在执行效率方面的差异,代码如下:
... suite .add('全局变量', () => { // 该函数内模拟全局作用域 let i, str = '' for (i = 0; i < 1000; i++) { str += i } }) .add('局部变量', () => { for (let i = 0, str = ''; i < 1000; i++) { str += i } }) ...
代码运行结果如下:
全局变量 x 158,697 ops/sec ±1.05% (87 runs sampled)
局部变量 x 160,697 ops/sec ±1.03% (90 runs sampled)
最快的是:局部变量
虽然说差异不大,但是我们可以感知全局变量比局部的性能更差一些。
为构造函数增加实例对象需要的方法时,尽量使用原型的方式添加,而不是构造函数内部进行添加,我们可以看如下测试代码:
... suite .add('构造函数内部添加', () => { function Person() { this.sayMe = function () { return '一碗周' } } let p = new Person() }) .add('原型方式内部添加', () => { function Person() {} Person.prototype.sayMe = function () { return '一碗周' } let p = new Person() }) ...
代码运行结果如下:
构造函数内部添加 x 573,786 ops/sec ±1.97% (89 runs sampled)
原型方式内部添加 x 581,693 ops/sec ±3.46% (80 runs sampled)
最快的是:构造函数内部添加
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,严重可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除 (即将局部变量重新赋值为null
)。
在JavaScript中的对象中,避免使用一些属性访问方法,这是因为JavaScript中的所有属性都是外部可见的。
示例代码如下:
... suite .add('使用属性访问方法', () => { function Person() { this.name = '一碗周' this.getName = function () { return '一碗周' } } let p = new Person() let n = p.getName() }) .add('不使用属性访问方法', () => { function Person() { this.name = '一碗周' } let p = new Person() let n = p.name }) ...
代码运行结果如下:
使用属性访问方法 x 406,682 ops/sec ±2.33% (82 runs sampled)
不使用属性访问方法 x 554,169 ops/sec ±2.03% (85 runs sampled)
最快的是:不使用属性访问方法
我们在使用for循环时,可以将有些必要的数据进行缓存,就比如arr.length
这种属性,不需要每次判断都获取一下,从而优化我们的代码。
示例代码如下:
... suite .add('正序', () => { let arr = new Array(100) let str = '' for (let i = 0; i < arr.length; i++) { str += i } }) .add('缓存', () => { let arr = new Array(100) let str = '' for (let i = arr.length; i; i--) { str += i } }) .add('缓存的另一种写法', () => { let arr = new Array(100) let str = '' for (let i = 0, l = arr.length; i < l; i++) { str += i } }) ...
代码运行结果如下:
正序 x 1,322,889 ops/sec ±1.36% (86 runs sampled)
缓存 x 1,356,696 ops/sec ±0.70% (92 runs sampled)
缓存的另一种写法 x 1,383,091 ops/sec ±0.70% (93 runs sampled)
最快的是:缓存的另一种写法
我们现在常用的循环有forEach
、for
和for...in
먼저 프로젝트에 종속성을 설치해야 합니다. 코드는 다음과 같습니다.
... suite .add('forEach', () => { let arr = new Array(100) let str = '' arr.forEach(i => { str += i }) }) .add('for...in', () => { let arr = new Array(100) let str = '' for (i in arr) { str += i } }) .add('for', () => { let arr = new Array(100) let str = '' for (let i = 0, l = arr.length; i < l; i++) { str += i } }) ...🎜그런 다음 테스트 코드를 다음과 같이 작성합니다. 🎜🎜
... /*** 接收两类文件,zip 和 rar* 压缩包的大小限制为 10 兆* / suite .add('嵌套写法', () => { function uploadFile(suffix, size) { // 允许上传的后缀名 const suffixList = ['.zip', '.rar'] const M = 1024* 1024 if (suffixList.includes(suffix)) { if (size <= 10* M) { return '下载成功' } } } uploadFile('.zip', 1* 1024* 1024) }) .add('减少判断写法', () => { function uploadFile(suffix, size) { // 允许上传的后缀名 const suffixList = ['.zip', '.rar'] const M = 1024* 1024 if (!suffixList.includes(suffix)) return if (size > 10* M) return return '下载成功' } uploadFile('.zip', 1* 1024* 1024) }) ...🎜🎜코드 실행 결과는 다음과 같습니다. 🎜🎜
🎜// Join1000 x 146,854 ops/sec ±1.86%(88회 실행 샘플링)🎜결과에서
// Join10000 x 16,083 ops/sec ±1.06%(92회 샘플링)
// 가장 빠른 속도: Join1000🎜
ops/sec
는 초당 실행 수를 나타냅니다. 물론 클수록 좋습니다. 그 다음에는 초당 실행 수의 상한과 하한의 백분율 차이가 옵니다. , 마지막으로 괄호 안의 내용은 총 샘플링 횟수를 나타냅니다. join1000
의 성능이 더 좋아진 것을 알 수 있습니다(말도 안 되는 소리를 하는 것 같은 느낌이 듭니다). 🎜🎜전역 변수를 주의해서 사용하세요🎜🎜🎜여기에 언급된 전역 변수를 주의해서 사용해야 하는 이유는 무엇입니까? 주요 사항은 다음과 같습니다. 🎜🎜... suite .add('before', () => { var name = '一碗粥' function sayMe() { name = '一碗周' function print() { var age = 18 return name + age } print() } sayMe() }) .add('after', () => { var name = '一碗粥' function sayMe() { var name = '一碗周' // 形成局部作用域 function print() { var age = 18 return name + age } print() } sayMe() }) ...🎜🎜코드 실행 결과는 다음과 같습니다.🎜 🎜
🎜전역 변수 x 158,697 ops/sec ±1.05%(87 실행 샘플링)🎜큰 차이는 아니지만, 로컬 변수에 비해 글로벌 변수의 성능이 떨어진다는 것을 느낄 수 있습니다. 🎜🎜프로토타입을 통해 메서드 추가🎜🎜인스턴스 개체에 필요한 메서드를 생성자에 추가할 때 생성자 내부에 추가하는 대신 프로토타입을 사용하여 추가해 보세요. 🎜
지역 변수 x 160,697 ops/sec ±1.03%(90 실행 샘플링)
가장 빠른 것은: 로컬 변수 🎜
... var userList = { one: { name: '一碗周', age: 18, }, two: { name: '一碗粥', age: 18, }, } suite .add('before', () => { function returnOneInfo() { userList.one.info = userList.one.name + userList.one.age } returnOneInfo() }) .add('after', () => { function returnOneInfo() { let one = userList.one one.info = one.name + one.age } returnOneInfo() }) ...🎜🎜실행 중인 코드입니다. 결과는 다음과 같습니다 :🎜🎜
🎜생성자는 내부적으로 x 573,786 ops/sec ±1.97%를 추가합니다(89 실행 샘플링)🎜를 추가하는 것입니다. 🎜🎜 클로저는 함수의 변수가 메모리에 저장되도록 하기 때문에 메모리 소비가 매우 크기 때문에 클로저 그렇지 않으면 웹 페이지에서 성능 문제가 발생하고 메모리 누수가 발생할 수도 있습니다. 해결 방법은 함수를 종료하기 전에 사용되지 않는 모든 지역 변수를 삭제하는 것입니다(즉, 지역 변수를
프로토타입 방법은 내부적으로 x 581,693 ops/sec ±3.46%(80 실행 샘플링)를 추가합니다
대부분 빠른 것은: 클로저에서 메모리 누수를 피하기 위해 생성자 내부에 🎜
null
에 다시 할당). 🎜🎜속성 액세스 방법을 사용하지 마세요.🎜🎜JavaScript의 개체에서는 일부 속성 액세스 방법을 사용하지 마세요. 이는 JavaScript의 모든 속성이 외부에서 표시되기 때문입니다. 🎜🎜🎜샘플 코드는 다음과 같습니다. 🎜🎜... suite .add('before', () => { var str = new String('string') }) .add('after', () => { var str = 'string' }) ...🎜🎜코드 실행 결과는 다음과 같습니다. 🎜🎜
🎜속성 액세스 방법 사용 x 406,682 ops/sec ±2.33%(82 실행 샘플링)🎜for 루프 최적화🎜🎜for를 사용할 때 루프에 필요한 데이터를 넣을 수 있습니다.
속성 액세스 방법을 사용하지 않음 x 554,169 ops/sec ±2.03%(85회 샘플링)
가장 빠른 방법은: 속성 액세스 방법을 사용하지 않는 것입니다🎜
arr.length
와 같은 캐싱 속성은 판단할 때마다 얻을 필요가 없으므로 코드를 최적화할 수 있습니다. 🎜🎜🎜샘플 코드는 다음과 같습니다. 🎜🎜rrreee🎜🎜코드 실행 결과는 다음과 같습니다. 🎜🎜🎜정방향 시퀀스 x 1,322,889 ops/sec ±1.36%(86 실행 샘플링)🎜 최적의 루프 방법 선택🎜🎜현재 우리가 일반적으로 사용하는 루프에는
캐시 x 1,356,696 ops/sec ±0.70%(92 실행 샘플링)
Cachex를 쓰는 또 다른 방법 1,383,091 ops/sec ±0.70%(93 실행 샘플링)
가장 빠른 방법: 캐시를 쓰는 또 다른 방법🎜
forEach
, for
및 for...in
루프가 포함됩니다. 이런 종류가 있나요? 테스트 코드는 다음과 같습니다. 🎜rrreee🎜🎜코드 실행 결과는 다음과 같습니다. 🎜🎜forEach x 4,248,577 ops/sec ±0.89% (86 runs sampled)
for...in x 4,583,375 ops/sec ±1.15% (91 runs sampled)
for x 1,343,871 ops/sec ±1.91% (88 runs sampled)
最快的是:for...in
由运行结果可以看出我们可以尽量使用for...in
或者forEach
循环,减少使用for
循环。
减少判断层级就是减少一些if
语句的嵌套,如果是一些必要的条件我们可以通过单层if
结合return
直接跳出函数的执行,关于优化前与优化后的代码执行比对如下所示:
... /*** 接收两类文件,zip 和 rar* 压缩包的大小限制为 10 兆* / suite .add('嵌套写法', () => { function uploadFile(suffix, size) { // 允许上传的后缀名 const suffixList = ['.zip', '.rar'] const M = 1024* 1024 if (suffixList.includes(suffix)) { if (size <= 10* M) { return '下载成功' } } } uploadFile('.zip', 1* 1024* 1024) }) .add('减少判断写法', () => { function uploadFile(suffix, size) { // 允许上传的后缀名 const suffixList = ['.zip', '.rar'] const M = 1024* 1024 if (!suffixList.includes(suffix)) return if (size > 10* M) return return '下载成功' } uploadFile('.zip', 1* 1024* 1024) }) ...
代码运行结果如下:
嵌套写法 x 888,445,014 ops/sec ±2.48% (88 runs sampled)
减少判断写法 x 905,763,884 ops/sec ±1.35% (92 runs sampled)
最快的是:减少判断写法,嵌套写法
虽然说差距并不是很大,但是不适用嵌套的代码比普通代码更优一些。
减少代码中作用域链的查找也是代码优化的一种方法,如下代码展示了两者的区别:
... suite .add('before', () => { var name = '一碗粥' function sayMe() { name = '一碗周' function print() { var age = 18 return name + age } print() } sayMe() }) .add('after', () => { var name = '一碗粥' function sayMe() { var name = '一碗周' // 形成局部作用域 function print() { var age = 18 return name + age } print() } sayMe() }) ...
代码运行结果如下:
before x 15,509,793 ops/sec ±7.78% (76 runs sampled)
after x 17,930,066 ops/sec ±2.89% (83 runs sampled)
最快的是:after
上面代码只是为了展示区别,并没有实际意义。
如果对象中的某个数据在一个代码块中使用两遍以上,这样的话将其进行缓存从而减少数据的读取次数来达到更优的一个性能,
测试代码如下:
... var userList = { one: { name: '一碗周', age: 18, }, two: { name: '一碗粥', age: 18, }, } suite .add('before', () => { function returnOneInfo() { userList.one.info = userList.one.name + userList.one.age } returnOneInfo() }) .add('after', () => { function returnOneInfo() { let one = userList.one one.info = one.name + one.age } returnOneInfo() }) ...
代码运行结果如下:
before x 222,553,199 ops/sec ±16.63% (26 runs sampled)
after x 177,894,903 ops/sec ±1.85% (88 runs sampled)
最快的是:before
凡是可以使用字面量方式声明的内容,绝对是不可以使用构造函数的方式声明的,两者在性能方面相差甚远,代码如下:
... suite .add('before', () => { var str = new String('string') }) .add('after', () => { var str = 'string' }) ...
代码运行结果如下:
before x 38,601,223 ops/sec ±1.16% (89 runs sampled)
after x 897,491,903 ops/sec ±0.92% (92 runs sampled)
最快的是:after
【相关推荐:javascript视频教程、web前端】
위 내용은 10가지 JavaScript 코드 최적화 팁 요약 및 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!