Maison > interface Web > js tutoriel > Une discussion approfondie sur les techniques d'optimisation des instructions de boucle dans les techniques JavaScript_javascript

Une discussion approfondie sur les techniques d'optimisation des instructions de boucle dans les techniques JavaScript_javascript

WBOY
Libérer: 2016-05-16 16:45:54
original
1141 Les gens l'ont consulté

Les boucles sont l'un des mécanismes les plus importants dans tous les langages de programmation. Presque tous les programmes informatiques ayant une signification pratique (tri, requête, etc.) ne contiennent pas de boucles. Les boucles sont également un élément très gênant de l'optimisation du programme.Nous devons souvent optimiser constamment la complexité du programme, mais nous sommes empêtrés dans le choix entre la complexité temporelle et la complexité spatiale à cause des boucles.

En javascript, il existe trois types de boucles natives, for () {}, while () {} et do {} while (), parmi lesquelles for () {} est la plus couramment utilisée.

Cependant, for est le type de boucle que les ingénieurs JavaScript ignorent le plus facilement lors de l'optimisation des programmes.

Passons d’abord en revue les connaissances de base de for.
La syntaxe for de JavaScript est héritée du langage C. Il existe deux manières d'utiliser la syntaxe de base de la boucle for.

1. Tableau de boucles

Syntaxe de base de la boucle for

Copier le code Le code est le suivant :

pour ( /* Initialisation*/2/ * Condition de jugement */2 /* Traitement de boucle*/ ) {
//... Code logique
}

Nous utilisons un exemple de code pour expliquer en détail.

Copier le code Le code est le suivant :

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

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

console.log('La somme des éléments du tableau est %d.', sum);
//=> La somme des éléments du tableau est 15.

Dans ce code, nous définissons et initialisons d'abord un tableau pour stocker les éléments à accumuler et une somme variable entière. Ensuite, nous commençons à boucler. Dans le code d'initialisation de la boucle for, nous avons également défini et initialisé deux variables : i (compteur) et len ​​(alias pour la longueur du tableau de boucle). Lorsque i est inférieur à len, la condition de boucle est établie et le code logique. est exécuté; chaque fois que la logique Après l'exécution du code, i est incrémenté de 1.

Dans le code logique de la boucle, nous ajoutons l'élément actuel du tableau de boucle à la variable somme.
Ce cycle est représenté par un organigramme comme suit :

Une discussion approfondie sur les techniques d'optimisation des instructions de boucle dans les techniques JavaScript_javascript

À partir de cet organigramme, nous pouvons facilement constater que le corps réel de la boucle dans le programme inclut non seulement notre code logique, mais inclut également le jugement d'exécution et le traitement de la boucle pour implémenter la boucle elle-même. .
De cette façon, nos idées d'optimisation sont claires et nous pouvons optimiser sous quatre aspects.

1. Code d'initialisation avant le corps de la boucle
2. Conditions de jugement d'exécution dans le corps de la boucle
3. Code logique
4. Code de traitement après le code logique

ps : Il existe une relation importante entre le premier point et le deuxième point.


1.1 Optimiser le code d'initialisation et les conditions de jugement d'exécution

Regardons d’abord un morceau de code que tout le monde connaît très bien.

Copier le code Le code est le suivant :

// faux !
pour ( var i = 02 i < list.length2 i) {
//... Code logique
>

Je crois que la plupart des ingénieurs qui écrivent du JavaScript utilisent toujours cette méthode de boucle apparemment normale, mais pourquoi est-ce que je dis que c'est faux ici ?
Démontons tout dans cette boucle et jetons un coup d'oeil :

1. Code d'initialisation - Cette boucle définit et initialise uniquement une variable de compteur.
2. Condition de jugement d'exécution - vraie lorsque le compteur est inférieur à la longueur de la liste.
3. Code de traitement - le compteur augmente de 1.

Revoyons à nouveau l'organigramme ci-dessus. Trouvons-nous quelque chose qui ne va pas ?
Le corps réel de la boucle contient non seulement notre code logique, mais inclut également le jugement d'exécution et le code de traitement pour implémenter la boucle elle-même. En d'autres termes, la condition de jugement i Vous semblez comprendre quelque chose ? Il existe deux opérations pour cette condition de jugement : 1. Interrogez l'attribut length dans le tableau list ; 2. Comparez les tailles de i et list.length ;
En supposant que le tableau liste contient n éléments, le programme doit effectuer 2n opérations dans le jugement d'exécution de cette boucle.

Si nous changeons le code par ceci :

Copier le code Le code est le suivant :

// Eh bien
pour (var je = 0 , len = liste.longueur; je < len;

Dans ce code amélioré, nous avons ajouté une définition et initialisé une variable len dans le code d'initialisation avant l'exécution du corps de la boucle, qui est utilisée pour stocker la valeur de list.length (à propos des variables, expressions, pointeurs et valeurs). le contenu sera abordé dans la deuxième partie). De cette façon, nous n'avons pas besoin d'interroger à nouveau les attributs du tableau de liste dans le jugement d'exécution dans le corps de la boucle, et le nombre d'opérations est la moitié de celui d'origine.

Nous avons amélioré la complexité temporelle de l'algorithme dans les étapes ci-dessus, mais si nous voulons continuer à optimiser la complexité spatiale, que devons-nous faire ? Si votre code logique n'est pas limité par l'ordre des boucles, vous pouvez essayer les méthodes d'optimisation suivantes.

Copier le code Le code est le suivant :

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

Ce code inverse l'ordre de la boucle, démarre le compteur i à partir du dernier index d'élément (list.length - 1) et effectue une boucle vers l'avant. Afin de réduire le nombre de variables requises pour la boucle à 1, et dans le jugement d'exécution, le nombre de requêtes de variables est réduit, et le temps nécessaire avant l'exécution de l'instruction CPU est réduit.

1.2 Optimiser le code logique

Dans la boucle, on récupère naturellement l'élément courant du tableau de la boucle afin d'effectuer certaines opérations sur lui ou de l'utiliser, ce qui entraînera inévitablement plusieurs appels à l'élément.

Copier le code Le code est le suivant :

var array = [
{ nom : 'Will Wen Gunn', tapez : 'hentai' },
{ nom : 'Vill Lin', tapez : 'moegril' }
];

for (var i = array.length - 1; i >= 0; --i) {
console.log('Name: %s', array[i].name);
console.log('Il/Elle est un(n) %s', array[i].type);

console.log('rn');
}
/*=>
Nom : Vill Lin
Il/Elle est un(e) moegril

Nom : Will Wen Gunn
Il/Elle est un(e) hentai
*/

Dans ce code, le programme doit interroger les attributs de nom et de type de chaque élément du tableau. Si le tableau comporte n éléments, le programme effectue 4n recherches d'objets.

Copier le code Le code est le suivant :

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

Je pense que vous devez avoir pensé à une solution à ce moment-là, qui consiste à attribuer la valeur de l'élément actuel du tableau à une variable, puis à l'utiliser dans le code logique.

Copier le code Le code est le suivant :

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

for (var i = array.length - 1; i >= 0 && (person = array[i]); --i) {
console.log('Name : %s', person. name);
console.log('Il/Elle est un(e) %s', person.type);

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

Cela a l'air beaucoup plus beau.

Copier le code Le code est le suivant :

1. array[i] => var personne
2. personne.nom
3. personne.type

C'est un peu comme foreach dans emcascript5, mais il y a une grande différence entre les deux, donc je ne l'expliquerai pas ici.

ps : Merci pour la correction de chacun. Après des expériences, nous avons appris que si les éléments du tableau sont définis par transfert direct de valeur, la valeur obtenue dans la boucle doit être une valeur, pas un pointeur. Ainsi, que vous définissiez des expressions ou des variables, des besoins en espace mémoire supplémentaires seront nécessaires.

1.3 Code de traitement optimisé

En fait, il n'y a pas grand chose qui puisse être optimisé dans le code de traitement dans le corps de la boucle, il suffit que le compteur i augmente de 1.
ps : Si vous avez de bonnes suggestions ou méthodes, veuillez les fournir. :)

2. Objet de boucle (objet)

En javascript, for peut également parcourir les propriétés et méthodes de l'objet. Il convient de noter que la boucle for ne peut pas traverser le type d'empaquetage auquel appartient l'objet ni les propriétés et méthodes du prototype (prototype) dans le constructeur.

La syntaxe est plus simple que de boucler un tableau.

Copier le code Le code est le suivant :

pour (/* initialisation*/ var key dans l'objet) {
//... Code logique
}

Nous utilisons souvent cette méthode pour faire fonctionner des objets.

Copier le code Le code est le suivant :

var person = {
'name ' : 'Will Wen Gunn',
'type' : 'hentai',
'compétence' : ['Programmation', 'Photographie', 'Parler', 'etc']
};

pour (var clé en personne) {
valeur = personne[clé];

// si la valeur est un tableau, convertissez-la en chaîne
if (value instanceof Array) {
value = value.join(', ');
}

console.log('%s: %s', key, value);
}
/*=>
nom : Will Wen Gunn
type : hentai
compétence : Programmation, Photographie, Prise de parole, etc
*/

Si vous avez déjà utilisé mongodb, vous connaissez certainement son mécanisme de requête. Parce que le mécanisme de requête de mongodb est comme l'âme de son API, la méthode flexible de fonctionnement du caillé a gagné à mongodb beaucoup de popularité et un élan de développement.

Dans l'implémentation de l'API mongo de nanodb, l'implémentation de la requête utilise largement les objets de boucle.

Copier le code Le code est le suivant :

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

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

_cursor
.sort({
étoile : 1
})
.toArray(function(err, rows) {
if (err)
return console.error( euh);

console.log(rows);
});

Ce que nous devons optimiser, ce n'est pas la boucle elle-même, mais l'optimisation des objets que vous devez parcourir.
Par exemple, la classe nanocollection dans nanodb, bien qu'elle ressemble à un tableau en surface, stocke tous les éléments, ou un objet, utilise l'identifiant de l'élément comme clé, puis stocke les éléments.

Mais ce n'est pas le cas. Les étudiants qui ont déjà utilisé le soulignement devraient connaître la méthode _.invert. C'est une méthode plutôt intéressante, elle inverse les clés et valeurs de l'objet passé.

Copier le code Le code est le suivant :

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

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

Si vous devez utiliser un objet boucle pour interroger la valeur de certaines propriétés de l'objet, vous pouvez essayer la méthode suivante.

Copier le code Le code est le suivant :

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

var name = 'Will Wen Gunn';

var _inverted = _.invert(personne);

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

Cependant, il n'y a pas grand-chose qui puisse être optimisé en utilisant pour la requête d'objet. Tout doit être basé sur les besoins réels. :p

Regardons ensuite les deux autres boucles, while () {} et do {} while (). Je crois que quiconque a suivi une formation en informatique connaît ces deux cycles. La seule différence entre eux est l'ordre logique dans lequel le corps de la boucle est exécuté.

La séquence d'exécution de while () {} est similaire à celle de for () {}. Le jugement d'exécution est avant le code logique, mais le code d'initialisation et de traitement est omis.
Lorsque la condition est donnée, le code logique est exécuté jusqu'à ce que la condition ne soit plus vraie.

Copier le code Le code est le suivant :

var sum = 0;

pendant que (somme < 10) {
somme = somme 1;
}

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

do {} while () place le jugement d'exécution après le code logique, c'est-à-dire "couper d'abord et jouer plus tard".

Copier le code Le code est le suivant :

somme var = 0;

faire {
somme = somme 1;
} while (somme < 10);

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

while () {} et do {} while () ne nécessitent pas non plus de compteur, mais utilisent certaines conditions pour déterminer s'il faut exécuter ou continuer à exécuter le code logique.

3. while () {} et fais {} while ()

while () {} et do {} while () sont principalement utilisés dans la logique métier pour effectuer en continu une série d'opérations pour atteindre un certain objectif, comme les files d'attente de tâches.

Mais ces deux types de boucles sont dangereux car ils ne sont contrôlés que par les conditions d'exécution par défaut. Si le code logique n'a aucun impact sur le jugement d'exécution, une boucle infinie se produira.

Copier le code Le code est le suivant :

var sum = 02

// avertissement !
while (somme < 10) {
somme = 1 12
}

Un tel code équivaut à while (true) {}, donc avant de l'utiliser, vous devez clarifier les conditions d'exécution et comment affecter les conditions d'exécution.

4. Faites bon usage des instructions de contrôle de boucle

Je crois que tous les ingénieurs JavaScript ont utilisé l'instruction break, mais l'instruction continue est relativement rarement utilisée. En fait, continue peut être trouvé dans de nombreux excellents projets open source JavaScript.

Afin de mieux comprendre la fonction de l'instruction continue, jetons d'abord un coup d'œil à un exemple de code

Copier le code Le code est le suivant :

// Serveur de diffusion Node.js
var net = require('net');
var util = require('util');

var BroadcastServer = net.createServer();

// Magasin client
broadcastServer.clients = [];

// Clients Broadcast Method
net.Socket.prototype.broadcast = function(msg) {
var clients = BroadcastServer.clients;
// Récupère le client qui publie la diffusion dans la collection Standard
var index = clients.indexOf(this);

for (var i = clients.length - 1; i >= 0; --i) {
if (i === index) {
// Si c'est le client qui publie le diffuser, Puis terminer la boucle en cours
continuer;
}

currClient = clients[i];

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

// Un nouveau client connecté
broadcastServer.on('connection', function(client) {
BroadcastServer.clients.push(client);

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

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

// Déconnecter le handle
client.on('end', function() {
client.broadcast('Left!');
})
});

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

Ce code implémente un serveur de diffusion basé sur le module net de node.js. Dans la méthode de diffusion, nous utilisons l'instruction continue pour envoyer des informations à toutes les connexions établies à l'exception du client qui publie le client de diffusion.

Le contenu du code est assez simple. Lorsqu'un client a besoin de publier une diffusion vers d'autres clients, la méthode de diffusion de l'objet client correspondant au client est appelée. Dans la méthode de diffusion, le programme obtiendra d'abord le cache. du client actuel. position index dans la collection de sockets client, puis publiez toutes les sockets client dans une boucle. Lorsque le compteur de boucle atteint l'index de position obtenu précédemment, le code logique dans le corps de la boucle actuelle est ignoré et la boucle suivante se poursuit. .

Je pense que les ingénieurs qui ont étudié le langage C/C recevront ce conseil de divers endroits : "N'utilisez pas d'instructions goto

."

Cette instruction goto "notoire" est en fait un contrôleur de flux de code. Les détails de l'instruction goto ne seront pas expliqués en détail ici. Cependant, JavaScript n'a pas d'instruction goto évidente, mais à partir des instructions break et continue, il n'est pas difficile de trouver l'ombre de goto en JavaScript.

En effet, les instructions break et continue permettent d'accepter un nom d'étiquette défini pour le saut de code.

Jetons un coup d'œil à l'exemple de code fourni par mdn.

Copier le code Le code est le suivant :

var i, j;

loop1:
for (i = 0; i < 3; i ) { //La première instruction for est étiquetée "loop1"
loop2:
for (j = 0; j < 3; j ) { //La deuxième instruction for est étiquetée "loop2"
if (i == 1 && j == 1) {
continue loop1;
console.log ("i = " i ", j = " j);
}
}
>

// La sortie est :

// "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"
// Remarquez comment il saute à la fois "i = 1, j = 1" et "i = 1, j = 2"

Dans cet exemple de code, deux niveaux de boucles sont implémentés et une étiquette est définie en dehors de chaque niveau de boucle pour les appels ultérieurs à l'instruction continue.

La première boucle est dans l'étiquette de loop1, ce qui signifie que dans le programme suivant, si l'étiquette loop1 est sélectionnée dans l'instruction continue ou l'instruction break, la boucle la plus externe sera sautée.

La boucle de deuxième niveau se trouve dans l'étiquette de loop2 dans la boucle de niveau supérieur. Si l'étiquette loop2 est sélectionnée dans l'instruction continue ou l'instruction break, elle reviendra au corps de la boucle de niveau supérieur.

En utilisant des instructions de contrôle de boucle, nous pouvons interférer avec le jugement d'exécution de la boucle d'origine, afin de pouvoir construire un système logique très complexe. En passant, il y a beaucoup d'instructions goto dans le noyau Linux. Quant à la raison pour laquelle nous entendons encore souvent des gens dire de ne pas utiliser d'instructions goto, il suffit de les rechercher sur Google.

5. Boucle avancée

5.1 Dérouler la boucle

Jetons d'abord un coup d'œil à deux morceaux de code. Devinez lequel a les meilleures performances.

Copier le code Le code est le suivant :

// Configuration
var array = [
  ["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA ", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES"],
  ["DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES" , "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES"],
  ["DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES"],
  ["DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", " DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
  ["DATA", "DATA", "DATA", "DATA", "DATA ", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES"],
  ["DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES" , "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES"],
  ["DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES", "DONNÉES"],
  ["DONNÉES", "DONNÉES", " DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"]
];
fonction processus( item) {
  // ​​Faire quelque chose avec l'item
}

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

// Cas 2
pour (var i = array.length - 1; i >= 0; i = i - 4) {
  for (var j = array[i].length - 1 ; j >= 0; j = j - 6) {
    processus(tableau[i][j]);
    processus(tableau[i][j - 1]);
    processus(tableau [i][j - 2]);
    process(array[i][j - 3]);
    process(array[i][j - 4]);
    process(array[i ][j - 5]);
  }
  for (var j = tableau[i - 1].length - 1; j >= 0; j = j - 6) {
    processus(tableau [i][j]);
    processus(array[i][j - 1]);
    processus(array[i][j - 2]);
    processus(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) {
    processus(array[i][j]);
    processus(array[i][j - 1]);
    processus(array[i][j - 2]);
    processus(array[i][j - 3]);
    processus(array[i][j - 4] );
    process(array[i][j - 5]);
  }
  for (var j = array[i - 3].length - 1; j >= 0; j = j - 6) {
    processus(array[i][j]);
    processus(array[i][j - 1]);
    processus(array[i][j - 2]);
    processus(array[i][j - 3]);
    processus(array[i][j - 4]);
    processus(array[i][j - 5]);
  >
}


我需要对array中的所有子数组的元素进行历遍,有两种方案,一种是我们平常所使用的方法,另一种是把循环任务展开。 答案是 case 2 性能更好,因为在每 6 个元素之间的执行判断都全部删除了,自然比往常的都要快。

这里我们来看看一种更给力的解决方案。 如果一个业务环节中需要对大数据集进行迭代处理,而这个数据集从开始迭代起,数据量不会再改变, 那麼可以考虑採用Il s'agit de Tom Duff. Il s'agit de Jeff Greenberg et de Javascript, ainsi que d'Andrew B. . roi 修改并提出了一种更为高效的版本。

复制代码 代码如下:

//crédit : Accélérez votre site (New Riders, 2003)
var itérations = Math.floor(values.length / 8);
var leftover = values.length % 8;
var i = 0;

if (restes > 0) {
  do {
    process(values[i ]);
  } while (--leftover > 0);
}
do {
  processus(valeurs[i ]);
  processus(valeurs[i ]);
  processus(valeurs[i ]);
  processus(valeurs[i ]);
  processus(valeurs [i ]);
  process(values[i ]);
  process(values[i ]);
  process(values[i ]);
} while (--itérations > 0 );

Les valeurs de valeur de valeur 8 sont plus importantes que math.floor().证结果为整数, 然后再计算不能被 8 jours ,并对这些元素单独进行处理,其餘则 8 次为单次展开次数来进行迭代。

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

复制代码 代码如下 :

fonction 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);
}
faire {
mapper(array[i]);
mapper(array[i]);
mapper(array[i]);
mapper(array[i] );
mapper(array[i]);
mapper(array[i]);
mapper(array[i]);
mapper(array[i]);
} tandis que (--n > 0);
}

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

Voici un ensemble de tests de performances et de résultats pour les trois solutions itératives ci-dessus. http://jsperf.com/spreaded-loop

5.2 Boucle non native

Dans n'importe quel langage de programmation, les boucles peuvent être implémentées non seulement via les instructions de boucle natives fournies par le langage, mais aussi indirectement via d'autres méthodes.

Revoyons d'abord un peu de contenu en mathématiques au lycée - la formule générale d'une séquence.

Copier le code Le code est le suivant :

à cause
a[1] = 1
a[n] = 2 * a[n - 1] 1

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

puis

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



Après avoir lu le calcul simple ci-dessus, vous avez peut-être deviné de quoi nous allons discuter. Oui, nous pouvons également utiliser la récursivité pour implémenter des boucles.

La récursion est une méthode d'application très importante en mathématiques et en informatique. Elle signifie qu'une fonction s'appelle lorsqu'elle est utilisée.

Dans la communauté node.js, la récursivité est utilisée pour implémenter une technologie très importante : la technologie middleware. Il s'agit d'un morceau de code d'implémentation de middleware dans une nouvelle version de webjs qui n'a pas encore été publiée.


Copier le code Le code est le suivant :

/**
 * Méthode d'exécution des middlewares
 * @param  {String} url URL de la requête actuelle
 * @param  {Object} demande l'objet de la requête
 * @param  {Object} res l'objet de réponse
 * @param  {Function} out Complete Callback
 * @return {Function}     le serveur
 */
server.runMiddlewares = function(url, req, res, out) {
  var index = -1;

  var middlewares = this._usingMiddlewares;

  // ​​exécute le prochain middleware s'il existe
  function next(err) {
    index ;

    // middleware actuel
    var curr = middlewares[index];

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

      // Vérifier l'itinéraire
      if (check.test(url)) {
        try {
           function later() {
            debug('Un middleware dit qu'il doit être plus tard % s', url);
            // Les dépendances ne fonctionnent pas pour le moment
            if (middlewares.indexOf(curr) !== middlewares.length - 1) {
               _later(curr);
             indice --;
              next();
            } else {
             debug('Une dépendance de middleware incorrecte');

              // Ce middleware ne peut pas s'exécuter
              out();
            }
          }

          // Exécuter le middleware
          if (utils.isFunc(curr.handler)) {

            // Fonction middleware normale
            curr.handler(req, res, next, later);

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

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

          } autre {

            // Il y a un problème avec le middleware
            next();

sinon {

// Passage à l'étape suivante du pipeline
      out();
    }
  }

  // ​​si le middleware dépend d'autres middlewares,
  // ​​il peut le laisser s'exécuter plus tard
  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;
  }

  // ​​premier middleware
  next();

 renvoyez ceci ;
};

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



复制代码

代码如下 :


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

var middlewares = this._usingMiddlewares;

// exécute le prochain middleware s'il existe
function next(err) {
index ;

// middleware actuel
var curr = middlewares[index];

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

// Vérifier l'itinéraire
if (check.test(url)) {
// exécuter le middleware actuel
curr.handler(req, res, next);
} else {
next();
}
} else {
// Passage à l'étape suivante du pipeline
out();
}
}

// premier middleware
next();

renvoie ceci ;
};

La raison pour laquelle la récursion peut être utilisée dans la mise en œuvre de systèmes middleware est que la récursion est la méthode de réponse de flux de programme la plus appropriée pour les E/S asynchrones dans node.js.

Dans ce code d'implémentation de middleware, this._usingmiddlewares est le tableau de boucles, la fonction next() est le corps de la boucle, check.test(url) est la condition de jugement d'exécution et le code de traitement de la boucle est le devant du corps de la boucle. . Le compteur d'index est incrémenté de 1 et la fonction suivante elle-même est appelée de manière récursive.

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal