Heim >Web-Frontend >js-Tutorial >Tipps zur Verbesserung der Leistung von JavaScript-Programmen mithilfe der Parameteranordnung von Function.apply()_javascript-Tipps

Tipps zur Verbesserung der Leistung von JavaScript-Programmen mithilfe der Parameteranordnung von Function.apply()_javascript-Tipps

WBOY
WBOYOriginal
2016-05-16 15:24:001353Durchsuche

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() >

Dies ähnelt tatsächlich etwas der unten aufgeführten „direkten Menge“. Versuchen Sie, interne Vorgänge zu verwenden, die zur Kompilierungszeit verwendet werden können, um schneller zu sein als Benutzervorgänge, die zur Laufzeit verwendet werden.

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.

3. Wenn für benutzerdefinierte Objekte die toString()-Methode für die Typkonvertierung definiert ist, wird empfohlen, toString() explizit aufzurufen, da die interne Operation die toString()-Methode des Objekts ausprobiert, nachdem sie alle Möglichkeiten getestet hat ob es in String konvertiert werden kann, daher ist der direkte Aufruf dieser Methode effizienter

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.


In ähnlicher Weise ist var foo = {} schneller als var foo = new Object(); und var reg = /../; ist schneller als var reg=new RegExp().

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:


Es ist schneller, einfach das zu verwenden, was sofort verfügbar ist. Beispielsweise sind lokale Variablen schneller als globale Variablen, direkte Variablen sind schneller als das Erstellen von Objekten zur Laufzeit usw.


Reduzieren Sie die Anzahl der Ausführungen so weit wie möglich, indem Sie beispielsweise zuerst diejenigen zwischenspeichern, die mehrere Abfragen erfordern.


Verwenden Sie so oft wie möglich integrierte Sprachfunktionen, wie z. B. String-Links.


Verwenden Sie so oft wie möglich die vom System bereitgestellten APIs, da diese APIs kompilierte Binärcodes sind und eine hohe Ausführungseffizienz aufweisen


同时,一些基本的算法上的优化,同样可以用在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。所以它不具备参考价值,于是我没有放在一开始给大家看。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn