Cet article vous apporte des connaissances pertinentes sur javascript. Il présente et résume principalement 10 conseils d'optimisation du code JavaScript. L'article présente le contenu en détail autour du sujet. J'espère qu'il sera utile à tout le monde.
[Recommandations associées : Tutoriel vidéo Javascript, front-end Web]
Si vous souhaitez optimiser le code JavaScript, la première chose que vous devez faire est de tester avec précision le code JavaScript. temps d'exécution du code. En fait, ce qu'il faut faire est de collecter un grand nombre d'échantillons d'exécution pour les statistiques et l'analyse mathématiques. Ici, nous utilisons benchmark.js
pour détecter l'exécution du code. 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
Nous devons d'abord installer les dépendances dans le projet, le code est le suivant :
... 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 exécutions échantillonnées)🎜Dans les résultats,
// join10000 x 16 083 ops/sec ±1,06 % (92 exécutions échantillonnées)
// Le plus rapide est : join1000🎜
ops/sec
représente le nombre d'exécutions par seconde. Bien sûr, plus c'est grand, mieux c'est, suivi de la différence en pourcentage entre le nombre supérieur et inférieur d'exécutions par seconde. . Enfin, le contenu entre parenthèses représente l'échantillonnage total combien de fois. On voit que les performances de join1000
sont meilleures (j'ai l'impression de dire des bêtises). 🎜🎜Utilisez les variables globales avec prudence🎜🎜🎜Les variables globales mentionnées ici doivent être utilisées avec prudence Pourquoi doivent-elles être utilisées avec prudence ? Les principaux points sont les suivants : 🎜🎜... 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() }) ...
🎜Variable globale x 158 697 ops/sec ±1,05 % (87 exécutions échantillonnées)🎜Bien que la différence ne soit pas grande, on sent que les performances des variables globales sont moins bonnes que celles des variables locales. 🎜🎜Ajouter des méthodes via le prototype🎜🎜Lors de l'ajout de méthodes requises pour les objets d'instance au constructeur, essayez de les ajouter à l'aide du prototype au lieu de les ajouter à l'intérieur du constructeur. Nous pouvons regarder le code de test suivant : 🎜
Variable locale x 160 697 ops/sec ±1,03 % (90 exécutions échantillonnées)
Le plus rapide est : variable locale 🎜
... 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() }) ...
🎜Le constructeur ajoute en interne x 573 786 ops/sec ±1,97% (89 exécutions échantillonnées)🎜 à l'intérieur du constructeur pour éviter les fuites de mémoire dans les fermetures 🎜🎜 Puisque les fermetures entraîneront la sauvegarde des variables de la fonction en mémoire, la consommation de mémoire est très importante, donc les fermetures ne peut pas être abusé, sinon cela entraînerait des problèmes de performances sur la page Web et pourrait même entraîner des fuites de mémoire. La solution est de supprimer toutes les variables locales inutilisées avant de quitter la fonction (c'est-à-dire de réaffecter les variables locales à
La méthode prototype ajoute en interne x 581 693 ops/sec ±3,46% (80 exécutions échantillonnées)
Le plus rapide : ajoutez 🎜
null
). 🎜🎜Évitez d'utiliser des méthodes d'accès aux propriétés🎜🎜Dans les objets en JavaScript, évitez d'utiliser certaines méthodes d'accès aux propriétés en effet, car toutes les propriétés en JavaScript sont visibles de l'extérieur. 🎜🎜🎜L'exemple de code est le suivant : 🎜🎜... suite .add('before', () => { var str = new String('string') }) .add('after', () => { var str = 'string' }) ...
🎜Utilisation de la méthode d'accès aux attributs x 406 682 ops/sec ±2,33 % (82 exécutions échantillonnées)🎜for optimisation de la boucle🎜🎜Lorsque nous utilisons le for boucle, nous pouvons mettre certaines données nécessaires. Les propriétés de mise en cache telles que
Ne pas utiliser la méthode d'accès aux attributs x 554 169 ops/sec ±2,03 % (85 exécutions échantillonnées)
Le plus rapide est : ne pas utiliser la méthode d'accès aux attributs🎜
arr.length
n'ont pas besoin d'être obtenues à chaque fois qu'elles sont jugées, optimisant ainsi notre code. 🎜🎜🎜L'exemple de code est le suivant : 🎜🎜rrreee🎜🎜Les résultats de l'exécution du code sont les suivants : 🎜🎜🎜Séquence avant x 1 322 889 ops/sec ±1,36 % (86 exécutions échantillonnées)🎜 Choisissez la méthode de boucle optimale 🎜🎜Les boucles que nous utilisons couramment incluent désormais les boucles
Cache x 1 356 696 ops/sec ±0,70 % (92 exécutions échantillonnées)
Une autre façon d'écrire le cachex 1 383 091 ops/sec ±0,70 % (93 exécutions échantillonnées)
La plus rapide est : une autre façon d'écrire le cache🎜
forEach
, for
et for...in
. ces types sont-ils ? Il a les meilleures performances. Le code de test est le suivant : 🎜rrreee🎜🎜Les résultats de l'exécution du code sont les suivants : 🎜🎜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前端】
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!