Heim > Artikel > Web-Frontend > Leistungsstarke JavaScript-Schleifenanweisungen und bedingte Anweisungen. Javascript-Kenntnisse
1. Schleifenanweisung
Wie wir alle wissen, gehören zu den häufig verwendeten Schleifenanweisungen for, while, do-while, for-in und forEach. Abgesehen davon, dass die Leistung von for-in und forEach etwas geringer ist, basiert unsere Auswahl der ersten drei normalerweise eher auf Bedürfnissen als auf Leistungsüberlegungen. Heute werden wir ihre jeweiligen Leistungen testen und uns sagen, dass sie immer noch die extremsten Leistungen erbringen können Fälle. Welche Optimierungen möglich sind.
Lassen Sie uns zunächst darüber sprechen, warum for-in und forEach langsamer sind als andere. for-in wird im Allgemeinen zum Durchlaufen von Objektattributnamen verwendet. Da jede Iterationsoperation gleichzeitig nach den Attributen der Instanz selbst und den Attributen in der Prototypenkette sucht, ist die Effizienz definitiv gering, während es sich bei forEach um eine funktionsbasierte Iteration handelt (Besondere Aufmerksamkeit ist erforderlich.) Allerdings wird dies nicht von allen IE-Versionen unterstützt. Bei Bedarf können Sie Bibliotheken wie JQuery verwenden. Der durch den Aufruf externer Methoden für jedes Array-Element verursachte Overhead ist der Hauptgrund für die langsame Geschwindigkeit.
Dann werfen wir einen Blick darauf, was „for“, „while“ und „do-while“ in jeder Iteration tun.
var length = items.length; for(var i = 0; i < length; i++) process(items[i]); var j = 0; while(j < length) process(items[j++]); var k = 0; do { process(items[k++]); } while(k < length);
In jeder Schleife oben wird dieser Vorgang jedes Mal ausgeführt, wenn der Schleifenkörper ausgeführt wird:
Wir können die Schleifenleistung verbessern, indem wir die Reihenfolge des Arrays umkehren:
for(var i = items.length; i--; ) process(items[i]); var j = items.length; while(j--) process(items[j]); var k = items.length - 1; do { process(items[k]); } while(k--);
In diesem Beispiel wird eine Schleife in umgekehrter Reihenfolge verwendet und die Subtraktionsoperation wird in die Schleifenbedingung integriert. Jetzt wird jede Kontrollbedingung einfach mit 0 verglichen. Die Kontrollbedingung wird mit einem wahren Wert verglichen. Jede Zahl ungleich Null wird automatisch in wahr umgewandelt, während ein Nullwert gleichbedeutend mit falsch ist. Tatsächlich wird die Kontrollbedingung von zwei Vergleichen (Ist die Anzahl der Iterationen kleiner als die Gesamtzahl? Ist sie wahr?) auf einen Vergleich (Ist sie wahr?) reduziert. Dies wird von zwei Vergleichen auf einen pro Iteration reduziert, wodurch die Schleifengeschwindigkeit weiter verbessert wird.
Leistungstest:
Ist das also wirklich so? Echtes Geld hat keine Angst vor der Browserverifizierung. Der Testcode ist sehr einfach und kapselt 8 Funktionen für 8 verschiedene Situationen (Profilinformationen können in Firefox nicht ohne Timer gedruckt werden, der Grund ist unbekannt):
// init array var a = []; var length = 10; for(var i = 0; i < length; i++) a[i] = 1; function for_in() { var sum = 0; for(var i in a) sum += a[i]; } function for_each() { var sum = 0; a.forEach(function(value, index, array) { sum += value; }); } function for_normal() { var sum = 0; for(var i = 0; i < length; i++) sum += a[i]; } function for_reverse() { var sum = 0; for(var i = length; i--; ) sum += a[i]; } function while_normal() { var sum = 0; var i = 0; while(i < length) sum += a[i++]; } function while_reverse() { var sum = 0; var i = length; while(i--) sum += a[i]; } function do_while_normal() { var sum = 0; var i = 0; do { sum += a[i++]; } while(i < length); } function do_while_reverse() { var sum = 0; var i = length - 1; do { sum += a[i]; } while(i--); } setTimeout(function() { console.profile(); for_in(); for_each(); for_normal(); for_reverse(); while_normal(); while_reverse(); do_while_normal(); do_while_reverse(); console.profileEnd(); }, 1000);
Wenn die Array-Länge 100 beträgt, haben wir festgestellt, dass die Ergebnisse unter Firefox tatsächlich den Erwartungen ähneln: for-each und for-in sind ineffizient, und die umgekehrte Reihenfolge ist etwas effizienter als die vorwärts gerichtete Reihenfolge. (Profile unter Chrome werden nicht angezeigt, da die Zeit zu kurz ist)
Wenn das Datenvolumen 1 Million erreicht, sind die Ergebnisse unter Firefox und Chrome wie erwartet, es gibt jedoch geringfügige Unterschiede. Die Leistung von for-in unter ff ist besser als die von for-each, aber die Leistung von for-in unter Chrome ist schlecht und es wird direkt eine Warnung ausgegeben. Obwohl die Leistung der umgekehrten Iteration leicht verbessert wird, ist die Verbesserung nicht groß und die Lesbarkeit des Codes wird verringert.
Zusammenfassung:
2. Bedingte Anweisungen
Zu den gängigen bedingten Anweisungen gehören „if-else“ und „switch-case“. Wann sollte man also die if-else-Anweisung und wann die „switch-case“-Anweisung verwenden?
Sehen wir uns zunächst den Code einer einfachen if-else-Anweisung an:
if (value == 0){ return result0; } else if (value == 1){ return result1; } else if (value == 2){ return result2; } else if (value == 3){ return result3; } else if (value == 4){ return result4; } else if (value == 5){ return result5; } else if (value == 6){ return result6; } else if (value == 7){ return result7; } else if (value == 8){ return result8; } else if (value == 9){ return result9; } else { return result10; }
Im schlimmsten Fall (Wert=10) müssen wir möglicherweise 10 Urteile fällen, bevor wir das richtige Ergebnis zurückgeben. Wie optimieren wir diesen Code? Eine offensichtliche Optimierungsstrategie besteht darin, den wahrscheinlichsten Wert im Voraus zu beurteilen. Beispielsweise ist der Wert am wahrscheinlichsten 5 oder 10, und dann werden diese beiden Beurteilungen im Voraus vorgenommen. Aber normalerweise wissen wir es nicht (die wahrscheinlichste Wahl). In diesem Fall können wir eine Binärbaum-Suchstrategie zur Leistungsoptimierung anwenden.
if (value < 6){ if (value < 3){ if (value == 0){ return result0; } else if (value == 1){ return result1; } else { return result2; } } else { if (value == 3){ return result3; } else if (value == 4){ return result4; } else { return result5; } } } else { if (value < 8){ if (value == 6){ return result6; } else { return result7; } } else { if (value == 8){ return result8; } else if (value == 9){ return result9; } else { return result10; } } }
这样优化后我们最多进行4次判断即可,大大提高了代码的性能。这样的优化思想有点类似二分查找,和二分查找相似的是,只有value值是连续的数字时才能进行这样的优化。但是代码这样写的话不利于维护,如果要增加一个条件,或者多个条件,就要重写很多代码,这时switch-case语句就有了用武之地。
将以上代码用switch-case语句重写:
switch(value){ case 0: return result0; case 1: return result1; case 2: return result2; case 3: return result3; case 4: return result4; case 5: return result5; case 6: return result6; case 7: return result7; case 8: return result8; case 9: return result9; default: return result10; }
swtich-case语句让代码显得可读性更强,而且swtich-case语句还有一个好处是如果多个value值返回同一个结果,就不用重写return那部分的代码。一般来说,当case数达到一定数量时,swtich-case语句的效率是比if-else高的,因为switch-case采用了branch table(分支表)索引来进行优化,当然各浏览器的优化程度也不一样。
除了if-else和swtich-case外,我们还可以采用查找表。
var results = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10]; //return the correct result return results[value];
当数据量很大的时候,查找表的效率通常要比if-else语句和swtich-case语句高,查找表能用数字和字符串作为索引,而如果是字符串的情况下,最好用对象来代替数组。当然查找表的使用是有局限性的,每个case对应的结果只能是一个取值而不能是一系列的操作。
小结:
以上就是本文的全部内容,希望对大家的学习有所帮助。