Heim >Web-Frontend >js-Tutorial >Tipps zur Verbesserung der Leistung von JavaScript-Programmen mithilfe der Parameteranordnung von Function.apply()_javascript-Tipps
Lassen Sie uns über die Fähigkeiten von Function.apply() bei der Verbesserung der Programmleistung sprechen.
Beginnen wir mit der Funktion Math.max(), auf die eine beliebige Anzahl von Parametern folgen kann und die schließlich den Maximalwert aller Parameter zurückgibt.
Zum Beispiel
alert(Math.max(5,8)) //8 alert(Math.max(5,7,9,3,1,6)) //9
Aber in vielen Fällen müssen wir das größte Element im Array finden.
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; }
So zu schreiben ist umständlich und ineffizient. Wenn Sie apply verwenden, sehen Sie sich den Code an:
function getMax2(arr){ return Math.max.apply(null,arr) }
Die beiden Codeteile erfüllen den gleichen Zweck, getMax2 ist jedoch viel eleganter, effizienter und prägnanter.
Schauen Sie sich den Leistungstest an:
getMax-Leistungstest
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 .不同的机器,结果可能有差异
Durch den Vergleich von 200.000 Daten beträgt die getMax2-Zeit 96 ms und die getmax-Zeit 464. Der Unterschied zwischen beiden beträgt das Fünffache
Ein weiteres Beispiel ist die Push-Methode eines Arrays.
var arr1=[1,3,4]; var arr2=[3,4,5];
Wenn wir arr2 erweitern und dann nacheinander an arr1 anhängen möchten, sei schließlich arr1=[1,3,4,3,4,5]
arr1.push(arr2) funktioniert offensichtlich nicht. Denn wenn Sie dies tun, erhalten Sie [1,3,4, [3,4,5] ]
Wir können eine Schleife nur verwenden, um einen nach dem anderen zu pushen (natürlich können Sie auch arr1.concat(arr2) verwenden, aber die Concat-Methode ändert arr1 selbst nicht)
var arrLen=arr2.length for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]) }
Seit wir Apply haben, sind die Dinge so einfach geworden
Array.prototype.push.apply(arr1,arr2)
Anhang: So optimieren Sie die Leistung von JavaScript-Skripten
Mit der Entwicklung des Internets und der Verbesserung der Netzwerk- und Maschinengeschwindigkeit nutzen immer mehr Websites Rich-Client-Technologie. Mittlerweile ist Ajax die beliebteste Methode. JavaScript ist eine interpretierte Sprache. Ob sie also das gleiche Niveau wie C/Java erreichen kann, schränkt ihre Möglichkeiten auf dem Client ein. Um ihre Leistung zu verbessern, möchte ich auf dem aufbauen, was ich zuvor für JavaScript getan habe Ich spreche über meine eigenen Erfahrungen und hoffe, jedem dabei zu helfen, die Leistung seines JavaScript-Skripts zu verbessern.
Sprachniveau
Schleife
Schleife ist eine sehr häufig verwendete Kontrollstruktur. In JavaScript können wir drei Arten von Schleifen verwenden: for(;;), und for(in). Dies Die Effizienz von for(in) unter den drei Arten von Schleifen ist äußerst schlecht, da der Hash-Schlüssel abgefragt werden muss, daher sollte er nach Möglichkeit so wenig wie möglich verwendet werden. Die Leistung von for(;;) und while-Schleife sollte grundsätzlich als gleichwertig bezeichnet werden (bei Verwendung im täglichen Gebrauch).
Tatsächlich ist die Verwendung dieser beiden Schleifen sehr speziell. Ich hatte bei meinen Tests einige interessante Situationen, siehe Anhang. Das abschließende Fazit lautet:
Wenn die Schleifenvariable inkrementiert oder dekrementiert wird, weisen Sie der Schleifenvariablen keinen Wert allein zu. Sie sollten beim letzten Lesen den verschachtelten ODER-Operator verwenden.
Wenn Sie die Länge des Arrays vergleichen möchten, sollten Sie das Längenattribut des Arrays vorab in eine lokale Variable einfügen, um die Anzahl der Abfragen zu reduzieren.
Lokale Variablen und globale Variablen
Auf lokale Variablen wird schneller zugegriffen als auf globale Variablen, da globale Variablen tatsächlich Mitglieder des globalen Objekts sind, während lokale Variablen auf dem Stapel der Funktion platziert werden.
Eval nicht verwenden
Die Verwendung von eval entspricht einem erneuten Aufruf der Interpretations-Engine, um den Inhalt zur Laufzeit auszuführen, was viel Zeit in Anspruch nimmt. Derzeit können Funktionsvorlagen mit von JavaScript unterstützten Abschlüssen implementiert werden (Einzelheiten zu Abschlüssen finden Sie in den relevanten Inhalten zur funktionalen Programmierung)
Objektsuche reduzieren
Aufgrund der Interpretierbarkeit von JavaScript erfordert a.b.c.d.e mindestens 4 Abfrageoperationen. Überprüfen Sie zuerst a, dann b in a, dann c in b und so weiter. Wenn solche Ausdrücke wiederholt auftreten, sollten sie daher so selten wie möglich gehalten werden. Sie können lokale Variablen verwenden, um sie für die Abfrage an einem temporären Ort abzulegen.
Dies kann mit einer Schleife kombiniert werden, da wir häufig eine Schleife basierend auf der Länge von Zeichenfolgen und Arrays durchführen müssen und diese Länge normalerweise unverändert bleibt. Beispielsweise ist jedes Mal, wenn a.length abgefragt wird, eine zusätzliche Operation erforderlich Wenn Sie var len=a.length im Voraus festlegen, gibt es eine Abfrage weniger.
String-Verkettung
Wenn Sie eine Zeichenfolge anhängen, verwenden Sie am besten die Operation s =anotherStr anstelle von s=s anotherStr.
Wenn Sie mehrere Zeichenfolgen verketten möchten, sollten Sie less = verwenden, z. B.
s =a;s =b;s =c; sollte als
geschrieben werden
s =a b c; und wenn Sie Zeichenfolgen sammeln, z. B. =-Operationen für dieselbe Zeichenfolge mehrmals ausführen, ist es am besten, einen Cache zu verwenden. Wie benutzt man es? Verwenden Sie zum Sammeln JavaScript-Arrays und verwenden Sie schließlich die Join-Methode zum Herstellen einer Verbindung wie folgt
var buf = new Array();for(var i = 0; i < 100; i++){ buf.push(i.toString());}var all = buf.join("");类型转换
Typkonvertierung ist ein häufiger Fehler, den jeder macht, da JavaScript eine dynamisch typisierte Sprache ist und Sie den Typ einer Variablen nicht angeben können.
1. Konvertieren Sie Zahlen in Zeichenfolgen und verwenden Sie „“ 1. Obwohl es etwas hässlich aussieht, ist dies tatsächlich das effizienteste, was die Leistung betrifft:
("" ) > String() > .toString() >
String() ist eine interne Funktion und daher sehr schnell, während .toString() die Funktion im Prototyp abfragt und daher nicht so schnell ist. Der neue String() wird verwendet, um eine exakte Kopie zurückzugeben.
2. Das Konvertieren von Gleitkommazahlen in Ganzzahlen ist fehleranfälliger. Tatsächlich wird parseInt() zum Konvertieren von Zeichenfolgen in Zahlen verwendet, nicht zwischen Gleitkommazahlen und Ganzzahlen sollte Math.floor() oder Math.round() verwenden.
Darüber hinaus ist Math im Gegensatz zu dem Problem bei der Objektsuche in Abschnitt 2 ein internes Objekt, sodass Math.floor() tatsächlich nicht viele Abfragemethoden und Aufrufzeiten aufweist und am schnellsten ist.
Direktmengen verwenden
Tatsächlich sind diese Auswirkungen relativ gering und können ignoriert werden. Was bedeutet es, direkte Mengen zu verwenden? JavaScript unterstützt beispielsweise die Verwendung von [param, param, param,...], um ein Array direkt auszudrücken. In der Vergangenheit haben wir alle new Array(param, param,...) verwendet. Ersteres wird direkt von der Engine interpretiert, letzteres ruft einen Array-internen Konstruktor auf und ist daher etwas schneller.
String-Traversal-Operation
Um Schleifenoperationen für Zeichenfolgen wie Ersetzen und Suchen auszuführen, sollten reguläre Ausdrücke verwendet werden, da die Schleifengeschwindigkeit von JavaScript selbst relativ langsam ist und die Operation regulärer Ausdrücke eine in C geschriebene API ist und die Leistung ebenfalls hoch ist sehr gut.
Erweiterte Objekte
Benutzerdefinierte erweiterte Objekte sowie Date- und RegExp-Objekte nehmen während der Erstellung viel Zeit in Anspruch. Wenn es wiederverwendet werden kann, sollte Caching verwendet werden.
DOM-bezogen
HTML einfügen
Viele Leute verwenden document.write gerne in JavaScript, um Inhalte für die Seite zu generieren. Tatsächlich ist dies weniger effizient. Wenn Sie HTML direkt einfügen müssen, können Sie ein Containerelement suchen, z. B. ein div oder span angeben, und dessen innerHTML so festlegen, dass Ihr eigener HTML-Code in die Seite eingefügt wird.
Objektabfrage
Die Verwendung von [""] zum Abfragen ist schneller als .items(). Dies entspricht der vorherigen Idee, die Objektsuche zu reduzieren und eine Abfrage und einen Funktionsaufruf hinzuzufügen.
DOM-Knoten erstellen
Normalerweise verwenden wir Zeichenfolgen, um HTML direkt zum Erstellen von Knoten zu schreiben, aber tatsächlich tun wir dies
Die Gültigkeit des Codes kann nicht garantiert werden
Die Effizienz des String-Betriebs ist gering
Sie sollten also die Methode document.createElement() verwenden, und wenn das Dokument einen vorgefertigten Vorlagenknoten enthält, sollten Sie die Methode cloneNode() verwenden, da dies nach Verwendung der Methode createElement() erforderlich ist Wenn Sie die Attribute des Elements mehrmals festlegen, kann die Verwendung von cloneNode() die Anzahl der Attributeinstellungen reduzieren. Wenn Sie viele Elemente erstellen müssen, sollten Sie ebenfalls zuerst einen Vorlagenknoten vorbereiten.
Timer
Wenn Sie auf Code abzielen, der ständig ausgeführt wird, sollten Sie nicht setTimeout, sondern setInterval verwenden. setTimeout setzt jedes Mal einen Timer zurück.
Andere
Skript-Engine
Meinem Test zufolge ist die Effizienz von Microsofts JScript deutlich schlechter als die von Mozillas Spidermonkey, sowohl was die Ausführungsgeschwindigkeit als auch die Speicherverwaltung betrifft, da JScript derzeit grundsätzlich nicht aktualisiert wird. Aber SpiderMonkey kann ActiveXObject nicht verwenden
Dateioptimierung
Dateioptimierung ist auch eine sehr effektive Methode. Löschen Sie alle Leerzeichen und Kommentare und fügen Sie den Code in eine Zeile ein, um den Download zu beschleunigen, und nicht die Analysegeschwindigkeit Leerzeichen haben keinen Einfluss auf die Interpretations- und Ausführungsgeschwindigkeit.
Zusammenfassung
Dieser Artikel fasst einige der Methoden zusammen, die ich in der JavaScript-Programmierung gefunden habe, um die Ausführungsleistung von JavaScript zu verbessern. Tatsächlich basieren diese Erfahrungen auf mehreren Prinzipien:
同时,一些基本的算法上的优化,同样可以用在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。所以它不具备参考价值,于是我没有放在一开始给大家看。