Heim > Web-Frontend > js-Tutorial > Eine ausführliche Diskussion über Optimierungstechniken für Schleifenanweisungen in JavaScript_Javascript-Techniken

Eine ausführliche Diskussion über Optimierungstechniken für Schleifenanweisungen in JavaScript_Javascript-Techniken

WBOY
Freigeben: 2016-05-16 16:45:54
Original
1138 Leute haben es durchsucht

Schleifen sind einer der wichtigsten Mechanismen in allen Programmiersprachen. Fast jedes Computerprogramm mit praktischer Bedeutung (Sortieren, Abfragen usw.) enthält keine Schleifen. Schleifen sind auch ein sehr problematischer Teil der Programmoptimierung. Wir müssen häufig die Komplexität des Programms ständig optimieren, sind jedoch aufgrund von Schleifen in die Wahl zwischen zeitlicher Komplexität und räumlicher Komplexität verstrickt.

In Javascript gibt es drei Arten von nativen Schleifen: for () {}, while () {} und do {} while (), von denen for () {} am häufigsten verwendet wird.

For ist jedoch die Art von Schleife, die JavaScript-Ingenieure bei der Optimierung von Programmen am leichtesten ignorieren.

Lassen Sie uns zunächst die Grundkenntnisse von for überprüfen.
Die for-Syntax von JavaScript wird von der C-Sprache übernommen. Es gibt zwei Möglichkeiten, die grundlegende Syntax der for-Schleife zu verwenden.

1. Schleifenarray

Grundlegende Syntax der for-Schleife

Code kopieren Der Code lautet wie folgt:

für ( /* Initialisierung*/2 / * Beurteilungsbedingung */2 /* Schleifenverarbeitung*/ ) {
//... Logikcode
}

Wir verwenden einen Beispielcode, um dies im Detail zu erklären.

Code kopieren Der Code lautet wie folgt:

var array = [1, 2, 3 , 4, 5];
var sum = 0;

for (var i = 0, len = array.length; i < len; i) {
sum = array[i];
}

console.log('Die Summe der Array-Elemente ist %d.', sum);
//=> Die Summe der Array-Elemente beträgt 15.

In diesem Code definieren und initialisieren wir zunächst ein Array zum Speichern der zu akkumulierenden Elemente und einer Summen-Ganzzahlvariablen. Als nächstes beginnen wir mit der Schleife. Im Initialisierungscode der for-Schleife haben wir außerdem zwei Variablen definiert und initialisiert: i (Zähler) und len (Alias ​​für die Länge des Schleifenarrays). Wenn i kleiner als len ist, wird die Schleifenbedingung erstellt und der Logikcode erstellt wird ausgeführt; jedes Mal, wenn die Logik ausgeführt wird, wird i um 1 erhöht.

Im Schleifenlogikcode fügen wir das aktuelle Schleifenarrayelement zur Summenvariablen hinzu.
Dieser Zyklus wird durch ein Flussdiagramm wie folgt dargestellt:

Eine ausführliche Diskussion über Optimierungstechniken für Schleifenanweisungen in JavaScript_Javascript-Techniken

Anhand dieses Flussdiagramms können wir leicht erkennen, dass der eigentliche Schleifenkörper im Programm nicht nur unseren Logikcode enthält, sondern auch die Ausführungsbeurteilung und Schleifenverarbeitung zur Implementierung der Schleife selbst .
Auf diese Weise sind unsere Optimierungsideen klar und wir können aus vier Aspekten optimieren.

1. Initialisierungscode vor dem Schleifenkörper
2. Ausführungsbeurteilungsbedingungen im Schleifenkörper
3. Logikcode
4. Verarbeitungscode nach dem Logikcode

ps: Es gibt eine wichtige Beziehung zwischen dem ersten und dem zweiten Punkt.


1.1 Initialisierungscode und Ausführungsbeurteilungsbedingungen optimieren

Schauen wir uns zunächst einen Code an, mit dem jeder sehr vertraut ist.

Code kopieren Der Code lautet wie folgt:

// falsch!
für ( var i = 02 i < list.length2 i) {
//... Logikcode
Ich glaube, dass die meisten Ingenieure, die JavaScript schreiben, immer noch diese scheinbar normale Schleifenmethode verwenden. aber warum sage ich, dass es hier falsch ist?
Lassen Sie uns alles in dieser Schleife auseinandernehmen und einen Blick darauf werfen:

1. Initialisierungscode – Diese Schleife definiert und initialisiert nur eine Zählervariable.

2. Ausführungsbeurteilungsbedingung – wahr, wenn der Zähler kleiner als die Länge der Liste ist.
3. Verarbeitungscode – der Zähler erhöht sich um 1.

Sehen wir uns das obige Flussdiagramm noch einmal an. Finden wir etwas Falsches?

Der eigentliche Schleifenkörper enthält nicht nur unseren Logikcode, sondern auch die Ausführungsbeurteilung und den Verarbeitungscode zur Implementierung der Schleife selbst. Mit anderen Worten: Die Beurteilungsbedingung i < list.length muss vor jeder Schleife ausgeführt werden. In JavaScript ist beim Lesen der Eigenschaften oder Methoden eines Objekts eine Abfrage erforderlich.
Du scheinst etwas zu verstehen? Für diese Beurteilungsbedingung gibt es zwei Operationen: 1. Fragen Sie das Längenattribut aus dem Listenarray ab. 2. Vergleichen Sie die Größen von i und list.length.
Angenommen, das Listenarray enthält n Elemente, muss das Programm bei der Ausführungsbeurteilung dieser Schleife 2n Operationen ausführen.

Wenn wir den Code wie folgt ändern:

Code kopieren Der Code lautet wie folgt:
// Nun
für (var i = 0 , len = list.length; i < i) {
//...

In diesem verbesserten Code haben wir eine Definition hinzugefügt und eine len-Variable im Initialisierungscode initialisiert, bevor der Schleifenkörper ausgeführt wird, die zum Speichern des Werts von list.length (über Variablen, Ausdrücke, Zeiger und Werte) verwendet wird Der Inhalt wird im zweiten Teil besprochen. Auf diese Weise müssen wir die Attribute des Listenarrays bei der Ausführungsbeurteilung im Schleifenkörper nicht erneut abfragen, und die Anzahl der Operationen beträgt die Hälfte der ursprünglichen.

Wir haben die zeitliche Komplexität des Algorithmus in den obigen Schritten verbessert, aber was sollten wir tun, wenn wir die räumliche Komplexität weiter optimieren möchten? Wenn Ihr Logikcode nicht durch die Schleifenreihenfolge eingeschränkt ist, können Sie die folgenden Optimierungsmethoden ausprobieren.

Code kopieren Der Code lautet wie folgt:

for (var i = list.length - 1; i >= 0; --i) {
//...
}

Dieser Code kehrt die Reihenfolge der Schleife um, startet den i-Zähler ab dem letzten Elementindex (list.length - 1) und führt eine Schleife vorwärts durch. Um die Anzahl der für die Schleife erforderlichen Variablen auf 1 und in der Ausführungsbeurteilung zu reduzieren, wird die Anzahl der Variablenabfragen reduziert und der Zeitaufwand vor der Ausführung des CPU-Befehls verringert.

1.2 Logikcode optimieren

In der Schleife erhalten wir auf natürliche Weise das aktuelle Array-Element der Schleife, um einige Operationen daran auszuführen oder es zu verwenden, was unweigerlich zu mehreren Aufrufen des Elements führt.

Code kopieren Der Code lautet wie folgt:

var array = [
{ name : 'Will Wen Gunn', Typ: 'hentai' },
{ Name: 'Vill Lin', Typ: 'moegril' }
];

for (var i = array.length - 1; i >= 0; --i) {
console.log('Name: %s', array[i].name);
console.log('Er/Sie ist ein(n) %s', array[i].type);

console.log('rn');
}
/*=>
Name: Vill Lin
Er/Sie ist ein/e Moegril

Name: Will Wen Gunn
Er/Sie ist ein(e) Hentai
*/

In diesem Code muss das Programm die Namens- und Typattribute jedes Array-Elements abfragen. Wenn das Array n Elemente hat, führt das Programm 4n Objektsuchen durch.

Code kopieren Der Code lautet wie folgt:

1. array[i]
2. array[i].name
3. array[i]
4. array[i].type

Ich glaube, Sie müssen zu diesem Zeitpunkt über eine Lösung nachgedacht haben, die darin besteht, den Wert des aktuellen Array-Elements einer Variablen zuzuweisen und ihn dann im Logikcode zu verwenden.

Code kopieren Der Code lautet wie folgt:

var array = [
{ name : 'Will Wen Gunn', Typ: 'hentai' },
{ Name: 'Vill Lin', Typ: 'moegril' }
];
var person = null;

for (var i = array.length - 1; i >= 0 && (person = array[i]); --i) {
console.log('Name: %s', person. name);
console.log('Er/Sie ist ein/e %s', person.type);

console.log('rn');
}
person = null;

Das sieht tatsächlich viel schöner aus.

Code kopieren Der Code lautet wie folgt:

1. array[i] => var person
2. person.name
3. person.type

Es ist ein bisschen wie foreach in emcascript5, aber es gibt einen großen Unterschied zwischen den beiden, deshalb werde ich es hier nicht erklären.

ps: Vielen Dank für die Korrektur. Nach Experimenten haben wir gelernt, dass der in der Schleife erhaltene Wert ein Wert und kein Zeiger sein muss, wenn die Elemente im Array durch direkte Werteübertragung definiert werden. Unabhängig davon, ob Sie Ausdrücke oder Variablen definieren, wird zusätzlicher Speicherplatz benötigt.

1.3 Optimierter Verarbeitungscode

Eigentlich gibt es im Verarbeitungscode im Schleifenkörper nicht viel zu optimieren. Es reicht aus, wenn der i-Zähler um 1 erhöht wird.
ps: Wenn Sie gute Vorschläge oder Methoden haben, geben Sie diese bitte an. :)

2. Schleifenobjekt (Objekt)

In Javascript kann for auch die Eigenschaften und Methoden von Objekten durchlaufen. Es ist zu beachten, dass die for-Schleife weder den Verpackungstyp, zu dem das Objekt gehört, noch die Prototypeigenschaften und -methoden (Prototyp) im Konstruktor durchlaufen kann.

Die Syntax ist einfacher als das Schleifen eines Arrays.

Code kopieren Der Code lautet wie folgt:

für (/* Initialisierung*/ var-Taste im Objekt) {
//... Logikcode
}

Wir verwenden diese Methode häufig zum Bedienen von Objekten.

Code kopieren Der Code lautet wie folgt:

var person = {
'name ' : ' Will Wen Gunn',
'Typ' : 'Hentai',
'Fähigkeit' : ['Programmieren', 'Fotografie', 'Sprechen', 'etc']
};

for (var key in person) {
value = person[key];

// Wenn der Wert ein Array ist, konvertieren Sie ihn in einen String
if (value instanceof Array) {
value = value.join(', ');
}

console.log('%s: %s', key, value);
}
/*=>
Name: Will Wen Gunn
Typ: Hentai
Fähigkeit : Programmieren, Fotografieren, Sprechen usw.
*/

Wenn Sie Mongodb jemals verwendet haben, sind Sie mit dem Abfragemechanismus auf jeden Fall vertraut. Da der Abfragemechanismus von Mongodb wie die Seele seiner API ist, hat die flexible Curd-Operationsmethode Mongodb große Popularität und Entwicklungsdynamik eingebracht.

In der Mongo-API-Implementierung von Nanodb verwendet die Abfrageimplementierung häufig Schleifenobjekte.

Code kopieren Der Code lautet wie folgt:

var myDB = nano.db('myDB ');
var myColl = myDB.collection('myColl');

var _cursor = myColl.find({
type : 'repo',
language : 'JavaScript'
});

_cursor
.sort({
star: 1
})
.toArray(function(err, rows) {
if (err)
return console.error( ähm);

console.log(rows);
});

Was wir optimieren müssen, ist nicht die Schleife selbst, sondern die Optimierung der Objekte, die Sie durchlaufen müssen.
Zum Beispiel speichert die Nanocollection-Klasse in Nanodb, obwohl sie auf der Oberfläche wie ein Array aussieht, alle Elemente oder ein Objekt, verwendet die ID des Elements als Schlüssel und speichert dann die Elemente.

Dies ist jedoch nicht der Fall. Schüler, die bereits Unterstriche verwendet haben, sollten die Methode _.invert kennen. Dies ist eine ziemlich interessante Methode, sie kehrt die Schlüssel und Werte des übergebenen Objekts um.

Code kopieren Der Code lautet wie folgt:

var person = {
'name ' : ' Will Wen Gunn',
'type' : 'hentai'
};

var _inverted = _.invert(person);
console.log(_inverted);
/*=>
{
'Will Wen Gunn' : 'name',
'hentai' : 'type'
}
*/

Wenn Sie ein Schleifenobjekt verwenden müssen, um den Wert einiger Eigenschaften des Objekts abzufragen, können Sie die folgende Methode ausprobieren.

Code kopieren Der Code lautet wie folgt:

var person = {
'name ' : ' Will Wen Gunn',
'type' : 'hentai'
};

var name = 'Will Wen Gunn';

var _inverted = _.invert(person);

if (_inverted[name] === 'name') {
console.log('Catched!');
}
//=> Catched!

Es gibt jedoch nicht viel, was für die Objektabfrage optimiert werden kann. Alles muss auf den tatsächlichen Anforderungen basieren. :p

Als nächstes schauen wir uns die anderen beiden Schleifen an, while () {} und {} while (). Ich glaube, dass jeder, der ein Informatikstudium absolviert hat, diese beiden Zyklen kennt. Der einzige Unterschied zwischen ihnen besteht in der logischen Reihenfolge, in der der Schleifenkörper ausgeführt wird.

Die Ausführungssequenz von while () {} ähnelt der von for () {}. Die Ausführungsbeurteilung erfolgt vor dem Logikcode, der Initialisierungs- und Verarbeitungscode wird jedoch weggelassen.
Wenn die Bedingung gegeben ist, wird der Logikcode ausgeführt, bis die Bedingung nicht mehr wahr ist.

Code kopieren Der Code lautet wie folgt:

var sum = 0;

while (sum < 10) {
sum = sum 1;
}

console.log(sum);
//=> 15

do {} while () setzt die Ausführungsbeurteilung nach dem Logikcode, d. h. „Zuerst schneiden und später abspielen“.

Code kopieren Der Code lautet wie folgt:

var sum = 0;

do {
sum = sum 1;
} while (sum < 10);

console.log(sum);
//=> 15

while () {} und do {} while () erfordern ebenfalls keinen Zähler, verwenden jedoch bestimmte Bedingungen, um zu bestimmen, ob der Logikcode ausgeführt oder weiterhin ausgeführt werden soll.

3. while () {} und {} while ()

while () {} und do {} while () werden hauptsächlich in der Geschäftslogik verwendet, um kontinuierlich eine Reihe von Vorgängen auszuführen, um einen bestimmten Zweck zu erreichen, z. B. Aufgabenwarteschlangen.

Aber diese beiden Arten von Schleifen sind gefährlich, da sie standardmäßig nur durch Ausführungsbedingungen gesteuert werden. Wenn der Logikcode keinen Einfluss auf die Ausführungsbeurteilung hat, entsteht eine Endlosschleife.

Code kopieren Der Code lautet wie folgt:

var sum = 02

// Warnung!
while (sum < 10) {
sum = 1 12
}

Ein solcher Code ist gleichbedeutend mit while (true) {}. Bevor Sie ihn verwenden, müssen Sie daher die Ausführungsbedingungen und die Auswirkungen auf die Ausführungsbedingungen klären.

4. Nutzen Sie Schleifenkontrollanweisungen sinnvoll

Ich glaube, dass alle JavaScript-Ingenieure die Break-Anweisung verwendet haben, die Continue-Anweisung jedoch relativ selten verwendet wird. Tatsächlich ist continue in vielen hervorragenden JavaScript-Open-Source-Projekten zu finden.

Um die Funktion der continue-Anweisung besser zu verstehen, schauen wir uns zunächst einen Beispielcode an

Code kopieren Der Code lautet wie folgt:

// Node.js Broadcast Server
var net = require('net');
var util = require('util');

var BroadcastServer = net.createServer();

// Client Store
broadcastServer.clients = [];

// Clients Broadcast Method
net.Socket.prototype.broadcast = function(msg) {
var client = BroadcastServer.clients;
// Holen Sie sich den Client, der die Übertragung in der Sammlung Standard veröffentlicht
var index = client.indexOf(this);

for (var i = client.length - 1; i >= 0; --i) {
if (i === index) {
// Wenn es der Client ist, der das veröffentlicht Broadcast, dann die aktuelle Schleife beenden
weitermachen;
}

currClient = client[i];

if (!currClient.destroyed) {
currClient.write(
util.format(
) 'r[Echo Client %s:%d] %snInput: ',
currClient. remoteAddress , currClient.remotePort, msg)
);
}
}
};

// Ein neuer Client ist verbunden
broadcastServer.on('connection', function(client) {
BroadcastServer.clients.push(client);

// Willkommen
client.write('[Broadcast Server] Welcome!nInput:');
client.broadcast(client, 'Joined!');

// Nachrichtenhandle
client.on('data', function(msg) {
client.broadcast(msg);
client.write('rInput:');
} );

// Handle trennen
client.on('end', function() {
client.broadcast('Left!');
})
});

// Bind
broadcastServer.listen(8080, function() {
console.log('Broadcast Serverbound.');
});

Dieser Code implementiert einen Broadcast-Server basierend auf dem Net-Modul von node.js. In der Broadcast-Methode verwenden wir die continue-Anweisung, um Informationen an alle hergestellten Verbindungen mit Ausnahme des Clients zu senden, der den Broadcast-Client veröffentlicht.

Der Inhalt des Codes ist recht einfach. Wenn ein Client eine Übertragung an andere Clients veröffentlichen muss, wird die Broadcast-Methode des Client-Objekts aufgerufen. Bei der Broadcast-Methode ruft das Programm zuerst den Cache ab des aktuellen Clients in der Client-Socket-Sammlung und veröffentlichen Sie dann alle Client-Sockets in einer Schleife. Wenn der Schleifenzähler den zuvor erhaltenen Positionsindex erreicht, wird der Logikcode im aktuellen Schleifenkörper übersprungen und die nächste Schleife fortgesetzt .

Ich glaube, dass Ingenieure, die C/C-Sprache studiert haben, von verschiedenen Seiten diesen Rat erhalten werden: „Verwenden Sie keine Goto-Anweisungen.“

Diese „berüchtigte“ goto-Anweisung ist eigentlich ein Codefluss-Controller. Die Details der goto-Anweisung werden hier nicht im Detail erläutert. JavaScript verfügt jedoch nicht über eine offensichtliche goto-Anweisung, aber anhand der break-Anweisung und der continue-Anweisung ist es nicht schwierig, den Schatten von goto in JavaScript zu finden.

Das liegt daran, dass die break-Anweisung und die continue-Anweisung das Akzeptieren eines definierten Labelnamens für den Codesprung ermöglichen.

Werfen wir einen Blick auf den von mdn bereitgestellten Beispielcode.

Code kopieren Der Code lautet wie folgt:

var i, j;

loop1:
for (i = 0; i < 3; i ) { //Die erste for-Anweisung trägt die Bezeichnung „loop1“
loop2:
for (j = 0; j < 3; j ) { //Die zweite for-Anweisung trägt die Bezeichnung „loop2“
if (i == 1 && j == 1) {
continue loop1;
console.log ("i = " i ", j = " j);
}
}
}

// Ausgabe ist:

// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// Beachten Sie, dass sowohl „i = 1, j = 1" als auch „i = 1, j = 2" übersprungen wird

In diesem Beispielcode werden zwei Schleifenebenen implementiert, und außerhalb jeder Schleifenebene wird eine Bezeichnung für nachfolgende Aufrufe der continue-Anweisung definiert.

Die erste Schleife befindet sich in der Beschriftung von Schleife1. Dies bedeutet, dass im nachfolgenden Programm die äußerste Schleife herausgesprungen wird, wenn die Beschriftung Schleife1 in der Continue-Anweisung oder der Break-Anweisung ausgewählt wird.

Die Schleife der zweiten Ebene befindet sich in der Beschriftung von Schleife2 in der Schleife der obersten Ebene. Wenn die Beschriftung Schleife2 in der Continue-Anweisung oder Break-Anweisung ausgewählt wird, kehrt sie zum Schleifenkörper der Schleife der obersten Ebene zurück.

Durch die Verwendung von Schleifenkontrollanweisungen können wir in die ursprüngliche Beurteilung der Schleifenausführung eingreifen, sodass wir ein sehr komplexes Logiksystem aufbauen können. Abgesehen davon gibt es im Linux-Kernel viele goto-Anweisungen. Warum wir immer noch oft sagen, man solle goto-Anweisungen nicht verwenden, googelt sie einfach.

5. Erweiterte Schleife

5.1 Schleife abrollen

Schauen wir uns zunächst zwei Codeteile an. Erraten Sie, welcher Code die bessere Leistung bietet.

Code kopieren Der Code lautet wie folgt:

// Setup
var array = [
  ["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA ", "DATA", "DATA", "DATA", "DATA"],
  ["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA" , „DATA“, „DATA“, „DATA“, „DATA“, „DATA“],
  [„DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“],
  [„DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „ DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“],
  [„DATA“, „DATA“, „DATA“, „DATA“, „DATA ", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
  ["DATA", "DATA", "DATA", "DATA" , „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“],
  [„DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“],
  [„DATA“, „DATA“, „ DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“, „DATA“]
];
Funktionsprozess( item) {
  // ​​Mach etwas mit item
}

// Fall 1
for (var i = array.length - 1; i >= 0; i--) {
  for (var j = array[i].length - 1; j >= 0; i--) {
    process(array[i][j]);
  }
}

// Fall 2
for (var i = array.length - 1; i >= 0; i = i - 4) {
  for (var j = array[i].length - 1 ; j >= 0; j = j - 6) {
    Process(array[i][j]);
    Process(array[i][j - 1]);
    Process(array [i][j - 2]);
    Process(array[i][j - 3]);
    Process(array[i][j - 4]);
    Process(array[i ][j - 5]);
  }
  for (var j = array[i - 1].length - 1; j >= 0; j = j - 6) {
    process(array [i][j]);
    Process(array[i][j - 1]);
    Process(array[i][j - 2]);
    Process(array[i][ j - 3]);
    Process(array[i][j - 4]);
    Process(array[i][j - 5]);
  }
  for (var j = array[i - 2].length - 1; j >= 0; j = j - 6) {
    Process(array[i][j]);
    Process(array[i][j - 1]);
    Process(array[i][j - 2]);
    Process(array[i][j - 3]);
    Process(array[i][j - 4] );
    Process(array[i][j - 5]);
  }
  for (var j = array[i - 3].length - 1; j >= 0; j = j - 6) {
    Process(array[i][j]);
    Process(array[i][j - 1]);
    Process(array[i][j - 2]);
    Process(array[i][j - 3]);
    Process(array[i][j - 4]);
    Process(array[i][j - 5]);
  }
}


我需要对array中的所有子数组的元素进行历遍,有两种方案,一种是我们平常所使用的方法, 另一种是把循环任务展开往常的都要快.

这里我们来看看一种更给力的解决方案。 环节中需要对大数据集进行迭代处理,而这个数据集从开始迭代起,数据量不会再改变, 那麼可以考虑採用一种名为 duff 装置的技术.这项技术是以其的创造者 tom duff 的名字来命名的, 这项技术最先实现於Beschreibung: Jeff Greenberg und Andrew B . König 修改并提出了一种更为高效的版本.

复制代码. 代码如下:

//Credit: Beschleunigen Sie Ihre Website (New Riders, 2003)
var iterations = Math.floor(values.length / 8);
var leftover = Values.length % 8;
var i = 0;

if (leftover > 0) {
  do {
    process(values[i ]);
  } while (--leftover > 0);
}
do {
  Process(values[i ]);
  Process(values[i ]);
  Process(values[i ]);
  Process(values[i ]);
  Process(values [i ]);
  Process(values[i ]);
  Process(values[i ]);
  Process(values[i ]);
} while (--iterations > 0 );

这种技术的工作原理是通过计算values的长度除以 8 以得到需要迭代的次数,并以math.floor()函数来保证结果为整数, 然后再计算不能被 8 整除时的餘数并对这些元素单独进行处理,其餘则 8 次为单次展开次数来进行迭代.

我将这种装置再加以封装,可以得到一种带有异步味道的 api

复制代码 代码如下:

function duff(array, mapper) {
var n = Math.floor(array.length / 8);
var l = array.length % 8;

var i = 0;
if (l > 0) {
do {
mapper(array[i ]);
} while (--i > 0);
}
do {
Mapper(array[i]);
Mapper(array[i]);
Mapper(array[i]);
Mapper(array[i] );
Mapper(array[i]);
Mapper(array[i]);
Mapper(array[i]);
Mapper(array[i]);
} while (--n > 0);
}

duff([...], function(item) {
//...
});

Hier finden Sie eine Reihe von Leistungstests und Ergebnissen für die oben genannten drei iterativen Lösungen. http://jsperf.com/spreaded-loop

5.2 Nicht-native Schleife

In jeder Programmiersprache können Schleifen nicht nur durch die von der Sprache bereitgestellten nativen Schleifenanweisungen, sondern auch indirekt durch andere Methoden implementiert werden.

Lassen Sie uns zunächst einige Inhalte der Oberstufenmathematik durchgehen – die allgemeine Formel einer Folge.

Code kopieren Der Code lautet wie folgt:

bacause
a[1] = 1
a[n] = 2 * a[n - 1] 1

also
                                                                                                                                                                                                                                               a[n] 1 = 2 * a[n - 1] 2 [n - 1] 1) = 2

dann

a[n] 1 = (a[n] 1) / (a[n - 1] 1) * (a[n - 1] 1) / (a[n - 2] 1) * ... * (a[2] 1) / (a[1] 1) * (a[i] 1)

a[n] 1 = 2 * 2 * ... * 2 * 2
a[n] 1 = 2^n
a[n] = 2^n - 1

final

a[n] = 2^n - 1



Nachdem Sie die obige einfache Berechnung gelesen haben, haben Sie vielleicht erraten, worüber wir sprechen werden. Ja, wir können Rekursion auch verwenden, um Schleifen zu implementieren.

Rekursion ist eine sehr wichtige Anwendungsmethode in der Mathematik und Informatik. Sie bedeutet, dass eine Funktion sich selbst aufruft, wenn sie verwendet wird.

In der Node.js-Community wird Rekursion verwendet, um eine sehr wichtige Technologie zu implementieren: Middleware-Technologie. Dies ist ein Teil des Middleware-Implementierungscodes in einer neuen Version von webjs, der noch nicht veröffentlicht wurde.


Code kopieren Der Code lautet wie folgt:

/**
 * Middleware-Ausführungsmethode
 * @param  {String} URL Aktuelle Anfrage-URL
 * @param  {Object} fordert das Anfrageobjekt an
 * @param  {Object} res das Antwortobjekt
 * @param  {Function} out Complete Callback
 * @return {Function}     den Server
 */
server.runMiddlewares = function(url, req, res, out) {
  var index = -1;

  var middlewares = this._usingMiddlewares;

  // ​​die nächste Middleware ausführen, falls vorhanden
  function next(err) {
    index ;

    // aktuelle Middleware
    var curr = middlewares[index];

    if (curr) {
      var check = new RegExp(curr.route);

      // Überprüfen Sie die Route
      if (check.test(url)) {
        try {
          function later() {
            debug('Eine Middleware sagt, dass es später sein muss % s', url);
            // Die Abhängigkeiten funktionieren derzeit nicht
            if (middlewares.indexOf(curr) !== middlewares.length - 1) {
             . _later(curr);
             Index --;
              next();
            } else {
              debug('Eine Middleware-Abhängigkeit ist falsch');

              // Diese Middleware kann nicht ausgeführt werden
              out();
            }
          }

          // Middleware ausführen
          if (utils.isFunc(curr.handler)) {

            // Normale Middleware-Funktion
            curr.handler(req, res, next, later);

          } else if (utils.isObject(curr.handler) && utils.isFunc(curr.handler.emit)) {

            // Serverobjekt
            curr.handler.emit('request', req, res, next, later);

          } sonst {

            // Mit der Middleware stimmt etwas nicht
            next();

          } } sonst {
// Zum nächsten Schritt der Pipeline
      out();
    }
  }

  // ​​wenn die Middleware von anderen Middlewares abhängt,
  // ​​kann sie später ausgeführt werden
  function _later(curr) {
    var i = middlewares.indexOf(curr);
var _tmp1 = middlewares.slice(0, i);
    _tmp1.push(middlewares[i 1], curr);

    var _tmp2 = middlewares.slice(i 2);

    [].push. apply(_tmp1, _tmp2);
    middlewares = _tmp1;
  }

  // ​​erste Middleware
  next();

  gib dies zurück;
};


虽然这段代码看上去狠复杂,不过如果我们对其精简之后,就清晰许多了.



复制代码


代码如下:


server.runMiddlewares = function(url, req, res, out) {
var index = -1;

var middlewares = this._usingMiddlewares;

// die nächste Middleware ausführen, falls vorhanden
function next(err) {
index ;

// aktuelle Middleware
var curr = middlewares[index];

if (curr) {
var check = new RegExp(curr.route);

// Route prüfen
if (check.test(url)) {
// aktuelle Middleware ausführen
curr.handler(req, res, next);
} else {
next();
}
} else {
// Zum nächsten Schritt der Pipeline
out();
}
}

// erste Middleware
next();

gib dies zurück;
};

Der Grund, warum Rekursion bei der Implementierung von Middleware-Systemen verwendet werden kann, liegt darin, dass Rekursion die am besten geeignete Programmfluss-Antwortmethode für asynchrone E/A in node.js ist.

In diesem Middleware-Implementierungscode ist this._usingmiddlewares das Schleifenarray, die Funktion next() ist der Schleifenkörper, check.test(url) ist die Ausführungsbeurteilungsbedingung und der Schleifenverarbeitungscode ist die Vorderseite des Schleifenkörpers . Der Indexzähler wird um 1 erhöht und die nächste Funktion selbst wird rekursiv aufgerufen.

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage