Parlons des compétences de Function.apply() pour améliorer les performances du programme.
Commençons par la fonction Math.max(). Math.max peut être suivi de n'importe quel nombre de paramètres, et renvoie enfin la valeur maximale parmi tous les paramètres.
Par exemple
alert(Math.max(5,8)) //8 alert(Math.max(5,7,9,3,1,6)) //9
Mais dans de nombreux cas, nous devons trouver le plus grand élément du tableau.
var arr=[5,7,9,1] alert(Math.max(arr)) // 这样却是不行的。一定要这样写 function getMax(arr){ var arrLen=arr.length; for(var i=0,ret=arr[0];i<arrLen;i++){ ret=Math.max(ret,arr[i]); } return ret; }
Écrire ainsi est fastidieux et inefficace. Si vous utilisez apply, regardez le code :
function getMax2(arr){ return Math.max.apply(null,arr) }
Les deux morceaux de code atteignent le même objectif, mais getMax2 est beaucoup plus élégant, efficace et concis.
Regardez le test de performance :
Test de performances getMax
var myArr=new Array() function fillRnd(arrLen){ //填入 arrLen个1-10的随机数字到数组 for(var i=0,arr=[];i<arrLen;i++){ arr[i]=Math.ceil(Math.random()*10) } return arr } function getMax(arr){ var arrLen=arr.length; for(var i=0,ret=arr[0];i<arrLen;i++){ ret=Math.max(ret,arr[i]); } return ret; } function getMax2(arr){ return Math.max.apply(null,arr) } myArr=fillRnd(20*10000) //生成20万个随机数填到数组 var t1=new Date() var max1=getMax(myArr) var t2=new Date() var max2=getMax2(myArr) var t3=new Date() if (max1!==max2) alert("error") alert([t3-t2,t2-t1]) //在我机器上 96,464 .不同的机器,结果可能有差异
En comparant 200 000 données, le temps getMax2 est de 96 ms et le temps getmax est de 464. La différence entre les deux est de 5 fois
Un autre exemple est la méthode push d'un tableau.
var arr1=[1,3,4]; var arr2=[3,4,5];
Si nous voulons développer arr2, puis ajouter à arr1 un par un, enfin laissez arr1=[1,3,4,3,4,5]
arr1.push(arr2) ne fonctionne évidemment pas. Parce que faire cela obtiendra [1,3,4, [3,4,5] ]
On ne peut utiliser qu'une boucle pour pousser un par un (bien sûr vous pouvez aussi utiliser arr1.concat(arr2) mais la méthode concat ne change pas arr1 elle-même)
var arrLen=arr2.length for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]) }
Depuis que nous avons Apply, les choses sont devenues si simples
Array.prototype.push.apply(arr1,arr2)
Pièce jointe : Comment optimiser les performances des scripts JavaScript
Avec le développement d'Internet et l'amélioration de la vitesse du réseau et de la vitesse des machines, de plus en plus de sites Web utilisent une technologie client riche. Ajax est désormais la méthode la plus populaire. JavaScript est un langage interprété, donc s'il peut atteindre le même niveau que C/Java, cela limite ce qu'il peut faire sur le client. Afin d'améliorer ses performances, je souhaite m'appuyer sur ce que j'ai fait pour JavaScript auparavant. parler de ma propre expérience, dans l'espoir d'aider tout le monde à améliorer les performances de ses scripts JavaScript.
Niveau de langue
Boucle
La boucle est une structure de contrôle très couramment utilisée. La plupart des choses en dépendent pour se terminer. En JavaScript, nous pouvons utiliser trois types de boucles : for(;;), while() et for(in). this L'efficacité de for(in) parmi les trois types de boucles est extrêmement faible car elle doit interroger la clé de hachage, elle doit donc être utilisée le moins possible si possible. Les performances des boucles for(;;) et while doivent être considérées comme fondamentalement équivalentes (lorsqu'elles sont utilisées au quotidien).
En fait, la façon d'utiliser ces deux boucles est très particulière. J'ai eu des situations intéressantes lors de mes tests, voir l'annexe. La conclusion finale est :
Si la variable de boucle incrémente ou décrémente, n'attribuez pas de valeur à la variable de boucle seule. Vous devez utiliser l'opérateur imbriqué ou - lors de sa dernière lecture.
Si vous souhaitez comparer avec la longueur du tableau, vous devez au préalable placer l'attribut de longueur du tableau dans une variable locale pour réduire le nombre de requêtes.
Variables locales et variables globales
Les variables locales sont accessibles plus rapidement que les variables globales, car les variables globales sont en fait membres de l'objet global, tandis que les variables locales sont placées sur la pile de la fonction.
Ne pas utiliser Eval
Utiliser eval équivaut à appeler à nouveau le moteur d'interprétation pour exécuter le contenu au moment de l'exécution, ce qui prend beaucoup de temps. À l'heure actuelle, les modèles de fonctions peuvent être implémentés à l'aide de fermetures prises en charge par JavaScript (pour plus de détails sur les fermetures, veuillez vous référer au contenu pertinent sur la programmation fonctionnelle)
Réduire la recherche d'objets
En raison de l'interprétabilité de JavaScript, a.b.c.d.e nécessite au moins 4 opérations de requête. Vérifiez d'abord a, puis vérifiez b dans a, puis vérifiez c dans b, et ainsi de suite. Par conséquent, si de telles expressions apparaissent à plusieurs reprises, ces expressions doivent rester aussi rares que possible. Vous pouvez utiliser des variables locales pour les placer dans un emplacement temporaire pour l'interrogation.
Cela peut être combiné avec le bouclage, car nous avons souvent besoin de boucler en fonction de la longueur des chaînes et des tableaux, et généralement cette longueur reste inchangée. Par exemple, chaque fois que a.length est interrogé, une opération supplémentaire est requise, et. Si vous définissez var len=a.length à l'avance, il y aura une requête de moins.
Concaténation de chaînes
Si vous ajoutez une chaîne, il est préférable d'utiliser l'opération s =anotherStr au lieu d'utiliser s=s anotherStr.
Si vous souhaitez concaténer plusieurs chaînes, vous devez utiliser less =, tel que
s =a;s =b;s =c; doit être écrit comme
s =a b c; et si vous collectez des chaînes, par exemple en effectuant plusieurs opérations = sur la même chaîne, il est préférable d'utiliser un cache. Comment l'utiliser ? Utilisez des tableaux JavaScript pour collecter, et enfin utilisez la méthode join pour vous connecter, comme suit
var buf = new Array();for(var i = 0; i < 100; i++){ buf.push(i.toString());}var all = buf.join("");类型转换
La conversion de type est une erreur courante que tout le monde commet, car JavaScript est un langage typé dynamiquement et vous ne pouvez pas spécifier le type d'une variable.
1. Convertissez les nombres en chaînes et utilisez "" 1. Même si cela semble un peu moche, c'est en fait le plus efficace, en termes de performances :
("" ) > String() > .toString() >
String() est une fonction interne, donc elle est très rapide, tandis que .toString() interroge la fonction dans le prototype, donc elle n'est pas aussi rapide que new String() est utilisée pour renvoyer une copie exacte.
2. La conversion de nombres à virgule flottante en nombres entiers est plus sujette aux erreurs. Beaucoup de gens aiment utiliser parseInt(). En fait, parseInt() est utilisé pour convertir des chaînes en nombres, pas entre des nombres à virgule flottante et des nombres entiers. devrait utiliser Math.floor() ou Math.round().
De plus, contrairement au problème de recherche d'objet de la section 2, Math est un objet interne, donc Math.floor() n'a en fait pas beaucoup de méthodes de requête et de temps d'appel, et est le plus rapide.
Utiliser des quantités directes
En fait, cet impact est relativement faible et peut être ignoré. Que signifie utiliser des quantités directes ? Par exemple, JavaScript prend en charge l'utilisation de [param, param, param,...] pour exprimer directement un tableau. Dans le passé, nous utilisions tous new Array(param, param,...) L'utilisation du premier est directement interprétée par le moteur, le second appelle un constructeur interne de Array, il est donc légèrement plus rapide.
Opération de traversée de chaîne
Pour effectuer des opérations de boucle sur des chaînes, telles que le remplacement et la recherche, des expressions régulières doivent être utilisées, car la vitesse de boucle de JavaScript lui-même est relativement lente et le fonctionnement des expressions régulières est une API écrite en C, et les performances sont très bien.
Objets avancés
Les objets avancés personnalisés et les objets Date et RegExp prendront beaucoup de temps pendant la construction. S'il peut être réutilisé, la mise en cache doit être utilisée.
Lié au DOM
Insérer du HTML
De nombreuses personnes aiment utiliser document.write en JavaScript pour générer du contenu pour la page. En fait, c'est moins efficace si vous devez insérer du HTML directement, vous pouvez rechercher un élément conteneur, tel que la spécification d'un div ou d'un span, et définir son innerHTML pour insérer votre propre code HTML dans la page.
Requête d'objet
Utiliser [""] pour interroger est plus rapide que .items() C'est la même chose que l'idée précédente de réduire la recherche d'objets. L'appel de .items() ajoute une requête et un appel de fonction.
Créer un nœud DOM
Habituellement, nous pouvons utiliser des chaînes pour écrire du HTML directement afin de créer des nœuds, mais en réalité, faites-le
La validité du code ne peut être garantie
L'efficacité du fonctionnement des chaînes est faible
Vous devez donc utiliser la méthode document.createElement(), et s'il y a un nœud de modèle prêt à l'emploi dans le document, vous devez utiliser la méthode cloneNode(), car après avoir utilisé la méthode createElement(), vous devez définissez les attributs de l'élément plusieurs fois, utilisez cloneNode() pour réduire le nombre de paramètres d'attribut - de même, si vous devez créer de nombreux éléments, vous devez d'abord préparer un nœud de modèle.
Minuterie
Si vous ciblez du code qui s'exécute en permanence, vous ne devez pas utiliser setTimeout, mais setInterval. setTimeout réinitialise une minuterie à chaque fois.
Autres
Moteur de script
D'après mon test, l'efficacité du JScript de Microsoft est bien pire que celle du Spidermonkey de Mozilla, à la fois en termes de vitesse d'exécution et de gestion de la mémoire, car JScript n'est fondamentalement pas mis à jour actuellement. Mais SpiderMonkey ne peut pas utiliser ActiveXObject
Optimisation des fichiers
L'optimisation des fichiers est également une méthode très efficace. Supprimez tous les espaces et commentaires et mettez le code sur une seule ligne pour accélérer le téléchargement plutôt que la vitesse d'analyse. S'il est local, les commentaires et. Les espaces n'affectent pas l'interprétation et la vitesse d'exécution.
Résumé
Cet article résume certaines des méthodes que j'ai trouvées dans la programmation JavaScript pour améliorer les performances d'exécution de JavaScript. En fait, ces expériences sont basées sur plusieurs principes :
同时,一些基本的算法上的优化,同样可以用在JavaScript中,比如运算结构的调整,这里就不再赘述了。但是由于JavaScript是解释型的,一般不会在运行时对字节码进行优化,所以这些优化仍然是很重要的。
当然,其实这里的一些技巧同样使用在其他的一些解释型语言中,大家也可以进行参考。
由于是以前做过的测试,测试代码已经不全,我补充了一部分如下:
var print; if(typeof document != "undefined" ){ print = function(){ document.write(arguments[0]); } }else if(typeof WScript != "undefined" ){ print = function(){ WScript.Echo(arguments[0],arguments[1],arguments[2]); } } function empty(){ } function benchmark(f){ var i = 0; var start = (new Date()).getTime(); while(i < pressure){ f(i++); } var end = (new Date()).getTime(); WScript.Echo(end-start); } /* i=0 start = (new Date()).getTime(); while(i < 60000){ c = [i,i,i,i,i,i,i,i,i,i]; i++; } end = (new Date()).getTime(); WScript.Echo(end-start); i=0 start = (new Date()).getTime(); while(i < 60000){ c = new Array(i,i,i,i,i,i,i,i,i,i); i++; } var end = (new Date()).getTime(); WScript.Echo(end-start); */ function internCast(i){ return "" + i; } function StringCast(i){ return String(i) } function newStringCast(i){ return new String(i) } function toStringCast(i){ return i.toString(); } function ParseInt(){ return parseInt(j); } function MathFloor(){ return Math.floor(j); } function Floor(){ return floor(j); } var pressure = 50000; var a = ""; var floor = Math.floor; j = 123.123; print("-------------\nString Conversion Test"); print("The empty:", benchmark(empty)); print("intern:", benchmark(internCast)); print("String:"); benchmark(StringCast); print("new String:"); benchmark(newStringCast); print("toString:"); benchmark(toStringCast); print("-------------\nFloat to Int Conversion Test"); print("parseInt"); benchmark(ParseInt); print("Math.floor"); benchmark(MathFloor); print("floor") benchmark(Floor); function newObject(){ return new Object(); } function internObject(){ return {}; } print("------------\nliteral Test"); print("runtime new object", benchmark(newObject)); print("literal object", benchmark(internObject));
附录2
代码1:
for(var i=0;i<100;i++){ arr[i]=0; }
代码2:
var i = 0; while(i < 100){ arr[i++]=0; }
代码3:
var i = 0; while(i < 100){ arr[i]=0; i++; }
在firefox下测试这两段代码,结果是代码2优于代码1和3,而代码1一般优于代码3,有时会被代码3超过;而在IE 6.0下,测试压力较大的时候(如测试10000次以上)代码2和3则有时候优于代码1,有时候就会远远落后代码1,而在测试压力较小(如5000次),则代码2>代码3>代码1。
代码4:
var i = 0; var a; while(i < 100){ a = 0; i++; }
代码5:
var a; for(var i=0;i<100;i++){ a = 0; }
上面两段代码在Firefox和IE下测试结果都是性能接近的。
代码6:
var a; var i=0; while(i<100){ a=i; i++; }
代码7:
var a; var i=0; while(i<100){ a=i++; }
代码8:
var a; for(var i=0;i<100;i++){ a = i; }
代码9:
var a; for(var i=0;i<100;){ a = i++; }
这四段代码在Firefox下6和8的性能接近,7和9的性能接近,而6, 8 < 7, 9;
最后我们来看一下空循环
代码10:
for(var i=0;i<100;i++){ }
代码11:
var i; while(i<100){ i++; }
最后的测试出现了神奇的结果,Firefox下代码10所花的时间与代码11所花的大约是24:1。所以它不具备参考价值,于是我没有放在一开始给大家看。