Les boucles sont l'un des mécanismes les plus importants de tous les langages de programmation, et les boucles ne sont pas ouvertes dans presque tous les programmes informatiques avec une signification pratique (tri, interrogatoire, etc.). Le bouclage est également une partie très gênante de l'optimisation du programme. Nous devons souvent optimiser constamment la complexité du programme, mais nous sommes enchevêtrés dans le choix entre la complexité du temps et la complexité de l'espace en raison de la boucle.
Dans JavaScript, il y a 3 boucles natives, pour () {}, while () {} et do {} while (), et les plus couramment utilisées sont pour () {}.
Cependant, car est la boucle la plus probable que les ingénieurs JavaScript ignorent lors de l'optimisation des programmes.
Prenons d'abord les connaissances de base de pour.
La syntaxe pour JavaScript est héritée du langage C, et il existe deux façons d'utiliser la syntaxe de base de pour les boucles.
1. Répanage de boucle
Syntaxe de base de la boucle pour
La copie de code est la suivante:
pour (/ * initialisation * / 2 / * Condition de jugement * / 2 / * Traitement de boucle * /) {
// ... code logique
}
Nous expliquerons en détail avec un code d'instance.
La copie de code est la suivante:
Var Array = [1, 2, 3, 4, 5];
var sum = 0;
pour (var i = 0, len = array.length; i <len; ++ i) {
sum + = array [i];
}
Console.log («La somme des éléments de la table / s est% d.», SUM);
// => La somme des éléments du tableau est de 15.
Dans ce code, nous définissons et initialisons d'abord un tableau qui stocke les éléments à accumuler et une variable de forme de somme. Ensuite, nous commençons la boucle. Dans le code d'initialisation de ceci pour la boucle, nous définissons et initialisons également deux variables: i (compteur) et len (alias de longueur de tableau de boucle). Lorsque je suis moins que Len, la condition de boucle est établie et le code logique est exécuté; Une fois chaque code logique exécuté, je serai incrémenté de 1.
Dans le code logique de la boucle, nous ajoutons les termes du tableau de la boucle actuelle à la variable de somme.
Ce cycle est représenté par l'organigramme comme suit:
À partir de ce graphique de flux, il n'est pas difficile de constater que le corps de boucle réel du programme contient non seulement notre code logique, mais comprend également le jugement d'exécution et le traitement de la boucle qui implémente la boucle elle-même.
De cette façon, nos idées d'optimisation seront claires et nous pouvons optimiser à partir de 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 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
Jetons d'abord un coup d'œil à un morceau de code que tout le monde connaît très bien.
La copie de code est la suivante:
// faux!
pour (var i = 02 i <list.length2 ++ i) {
// ... code logique
}
Je crois que la plupart des ingénieurs qui écrivent JavaScript utilisent toujours cette méthode de boucle apparemment normale, mais pourquoi est-ce que je dis que c'est mal ici?
Déliquons tout dans cette boucle et jetons un coup d'œil:
1. Initialiser le code - cette boucle définit et initialise une variable de compteur.
2. Condition du jugement d'exécution - Il est vrai lorsque le compteur est inférieur à la longueur de la liste.
3. Code de traitement - le compteur est incrémenté de 1.
Passons en revue l'organigramme ci-dessus et découvrons s'il y a quelque chose de mal à cela?
Le corps de boucle réel a non seulement notre code logique, mais comprend également le jugement d'exécution et le code de traitement qui implémente la boucle elle-même. En d'autres termes, la condition de jugement i <list.length doit être exécutée avant chaque boucle. Dans JavaScript, une requête est requise lors de la lecture des propriétés ou des méthodes d'un objet.
Vous semblez comprendre quelque chose, non? Il y a deux opérations dans cette condition de jugement: 1. Remettre l'attribut de longueur du tableau de liste; 2. Comparez les tailles de i et list.length.
En supposant que le tableau de liste contient n éléments, le programme doit effectuer des opérations 2n dans le jugement d'exécution de cette boucle.
Si nous modifions le code pour ceci:
La copie de code est la suivante:
// Bien
pour (var i = 0, len = list.length; i <len; ++ i) {
// ...
}
Dans ce code amélioré, nous avons ajouté une définition et initialisé une variable LEN pour stocker la valeur de List.Length dans le code d'initialisation avant l'exécution du corps de la boucle (le contenu pertinent sur les variables, les expressions, les pointeurs et les valeurs sera discuté dans le deuxième article). De cette façon, nous n'avons pas besoin d'interroger à nouveau le tableau de liste dans le jugement d'exécution dans le corps de la boucle, et l'opérande est la moitié de l'original.
Dans les étapes ci-dessus, nous avons amélioré la complexité temporelle de l'algorithme, et comment le faire si nous voulons continuer à optimiser la complexité de l'espace? Si votre code logique n'est pas limité par l'ordre de boucle, vous pouvez essayer la méthode d'optimisation suivante.
La copie de code est la suivante:
pour (var i = list.length - 1; i> = 0; --i) {
// ...
}
Ce code boucle en avant en inversant l'ordre de boucle, en commençant par le dernier indice d'élément (list.length - 1). Afin de réduire le nombre de variables requis pour la boucle à 1, et dans le jugement d'exécution, le nombre de requêtes variables est réduit et le temps passé avant d'exécuter l'instruction du CPU est réduit.
1.2 Optimisation du code logique
Dans une boucle, nous obtenons l'élément de tableau actuel de la boucle, naturellement pour faire des opérations dessus ou l'utiliser, ce qui conduit inévitablement à plusieurs appels à l'élément.
La copie de code est la suivante:
var array = [
{nom: 'Will Wen Gunn', type: 'hentai'},
{Name: 'Vill Lin', Type: 'Moegril'}
]]
pour (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] .ype);
console.log ('/ r / n');
}
/ * =>
Nom: Vill Lin
Il / elle est un (n) moegril
Nom: Will Wen Gunn
Il / elle est un (n) hentai
* /
Dans ce code, le programme doit interroger les attributs de nom et de type de chaque élément de tableau. Si le tableau contient n éléments, le programme effectuera des requêtes d'objet 4N.
La copie de code est la suivante:
1. Array [i]
2. Array [i] .Name
3. Array [i]
4. Array [i] .Type
Je crois que vous devez avoir pensé à une solution pour le moment, c'est-à-dire attribuer la valeur de l'élément de tableau actuel à une variable, puis l'utiliser dans le code logique.
La copie de code est la suivante:
var array = [
{nom: 'Will Wen Gunn', type: 'hentai'},
{Name: 'Vill Lin', Type: 'Moegril'}
]]
var personne = null;
for (var i = array.length - 1; i> = 0 && (personne = array [i]); --i) {
console.log ('name:% s', personne.name);
console.log ('il / elle est un (n)% s', personne.type);
console.log ('/ r / n');
}
personne = null;
Cela a l'air beaucoup plus beau.
La copie de code est la suivante:
1. Array [i] => var personne
2. Person.Name
3. Person.Type
C'est un peu comme le foreach dans Emcascript5, mais la différence entre les deux est énorme, donc je ne l'expliquerai pas ici.
PS: Merci pour votre correction. Après des expériences, j'ai constaté que si les éléments du tableau sont définis en passant directement les valeurs, la valeur obtenue dans la boucle doit être une valeur, pas un pointeur. Donc, que vous définissiez des expressions ou des variables, il y aura des demandes d'espace mémoire supplémentaires.
1.3 Optimiser le code de traitement
En fait, il n'y a pas grand-chose à optimiser le code de traitement dans le corps de la boucle, et le compteur I est suffisant pour augmenter le 1 seul.
PS: Si vous avez de bonnes suggestions ou méthodes, veuillez les fournir. :)
2. Objet circulaire (objet)
En JavaScript, peut également traverser les propriétés et les méthodes de l'objet. Il convient de noter que la boucle FOR ne peut pas passer par le type d'emballage auquel l'objet appartient ou les propriétés et méthodes prototypes du constructeur.
La syntaxe est plus simple que les tableaux en boucle.
La copie de code est la suivante:
pour (/ * initialiser * / var clé dans l'objet) {
// ... code logique
}
Nous utilisons souvent cette méthode pour fonctionner sur des objets.
La copie de code est la suivante:
var personne = {
«Nom»: «Will Wen Gunn»,
«Type»: «hentai»,
«Compétence»: [«Programmation», «photographie», «Speaking», «etc»]
};
pour (clé var en personne) {
valeur = personne [clé];
// Si la valeur est un tableau, convertissez-le en une chaîne
if (valeur de valeur du tableau) {
valeur = valeur.join (',');
}
console.log ('% s:% s', clé, valeur);
}
/ * =>
Nom: Will Wen Gunn
Type: hentai
Compétence: programmation, photographie, parole, etc.
* /
Si vous avez utilisé MongoDB, vous serez certainement familier avec 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 de fonctionnement flexible du caillé a valu à MongoDB beaucoup de popularité et d'élan de développement.
Dans la mise en œuvre de l'API Mongo de NANODB, la mise en œuvre de la requête utilise des objets de boucle à grande échelle.
La copie de code est la suivante:
var mydb = nano.db ('mydb');
var mycoll = mydb.collection ('mycoll');
var _cursor = myColl.find ({
Type: «repo»,
Langue: «JavaScript»
});
_curseur
.trier({
étoile: 1
})
.ToArray (fonction (err, lignes) {
if (err)
return console.error (err);
console.log (lignes);
});
Ce que nous devons optimiser n'est pas la boucle elle-même, mais l'optimisation des objets dont vous avez besoin.
Par exemple, la classe Nanocollection dans NanoDB ressemble à un tableau, qui contient tous les éléments ou objets, et utilise l'ID de l'élément comme clé puis stocke les éléments.
Mais ce n'est pas le cas. Les élèves qui ont utilisé des traits de soulignement devraient connaître la méthode _.invert. C'est une façon assez intéressante d'inverser les clés et les valeurs de l'objet transmis.
La copie de code est la suivante:
var personne = {
«Nom»: «Will Wen Gunn»,
'Type': 'hentai'
};
var _inverted = _.invert (personne);
console.log (_inverted);
/ * =>
{
'Will Wen Gunn': 'nom',
'hentai': 'type'
}
* /
Si vous avez besoin d'utiliser un objet de boucle pour interroger les valeurs de certaines propriétés de l'objet, vous pouvez essayer la méthode suivante.
La copie de code est la suivante:
var personne = {
«Nom»: «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 beaucoup d'optimisation à utiliser pour la requête d'objet, et tout doit être basé sur les besoins réels. : P
Ensuite, nous regardons les deux autres boucles, while () {} et do {} while (). Je crois que tout ami qui a reçu un cours d'informatique connaîtra ces deux cycles. La seule différence entre eux est l'ordre logique d'exécution du corps de la boucle.
L'ordre d'exécution de while () {} est similaire à celui de () {}. Les jugements d'exécution sont effectués avant le code logique, mais le code d'initialisation et de traitement est omis.
Lorsqu'une condition est donnée, le code logique est exécuté jusqu'à ce que la condition ne se maintient plus.
La copie de code est la suivante:
var sum = 0;
tandis que (sum <10) {
sum + = sum + 1;
}
console.log (sum);
// => 15
Do {} while () met le jugement d'exécution après le code logique, qui signifie "mort d'abord puis jouer".
La copie de code est la suivante:
var sum = 0;
faire {
sum + = sum + 1;
} while (sum <10);
console.log (sum);
// => 15
Tandis que () {} et do {} while () ne nécessitent pas non plus de compteur, mais utilisez certaines conditions pour déterminer s'il faut exécuter ou continuer à exécuter du code logique.
3. While () {} et do {} while ()
tandis que () {} et do {} while () sont principalement utilisés dans la logique métier, et une série d'opérations est en continu pour atteindre un certain objectif, telles que les files d'attente de tâches.
Mais ces deux boucles sont dangereuses car elles ne sont contrôlées que par les conditions d'exécution par défaut. S'il n'y a pas d'impact sur le jugement d'exécution dans le code logique, une boucle morte se produira.
La copie de code est la suivante:
var sum = 02
// avertissement!
tandis que (sum <10) {
somme = 1 + 12
}
Un tel code n'est pas différent de (vrai) {}, donc avant utilisation, il est nécessaire de clarifier les conditions d'exécution et comment affecter les conditions d'exécution.
4. faire bon usage des instructions de contrôle de boucle
Je crois que tous les ingénieurs JavaScript ont utilisé des instructions de rupture, mais les instructions de poursuite sont relativement rarement utilisées. En fait, il existe de nombreux excellents projets open source JavaScript qui peuvent être trouvés.
Afin de résoudre la fonction de l'instruction Continuer, jetons un coup d'œil à l'exemple de code d'abord
La copie de code est la suivante:
// Node.js Broadcast Server
var net = require ('net');
var util = require ('util');
var BroadCastServer = net.CreateServer ();
// Store client
BroadcastServer.Clients = [];
// Méthode de diffusion des clients
net.socket.prototype.broadcast = function (msg) {
VAR CLIENTS = BroadcastServer.Clients;
// obtient l'indice du client de diffusion dans le centralisé
var index = clients.indexof (this);
pour (var i = clients.length - 1; i> = 0; --i) {
if (i === index) {
// S'il s'agit d'un client de diffusion, le corps de boucle actuel sera terminé
continuer;
}
CurrClient = clients [i];
if (! currclient.destroyed) {
currclient.write (
util.format (
'/ r [echo client% s:% d]% s / ninput:',
currclient.remoteaddress, currclient.remoteport, msg)
));
}
}
};
// un nouveau client connecté
BroadcastServer.on ('Connection', fonction (client) {
BroadcastServer.Clients.push (client);
// Accueillir
client.write ('[Broadcast Server] Welcome! / Ninput:');
client.broadcast (client, «joint!»);
// Poignée de message
client.on ('data', fonction (msg) {
client.broadcast (msg);
client.write ('/ rinput:');
});
// Débrancher la poignée
client.on ('end', function () {
client.broadcast («Left!»);
})
});
// Lier
BroadcastServer.Listen (8080, fonction () {
Console.log («Broadcast Server Bound»);
});
Ce code implémente un serveur de diffusion basé sur le module NET Node.js. Dans la méthode de diffusion, nous utilisons l'instruction CONSTERNE pour implémenter tous les clients connectés qui ont établi des connexions à l'exception du client de diffusion.
Le contenu du code est assez simple. Lorsqu'un client doit diffuser à 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 l'indice de position du client actuel dans la collection de socket client en cache, puis parcourera toutes les prises clients. Lorsque le compteur de boucle atteint l'indice de position qu'il a obtenu auparavant, le code logique du corps de boucle actuel sera ignoré et la prochaine boucle se poursuivra.
Je crois que les ingénieurs qui ont appris la langue C / C ++ obtiendront ce conseil à partir de divers endroits: "N'utilisez pas les déclarations GOTO".
Cette instruction GOTO "notoire" est en fait un contrôleur de flux de code, et les détails de l'instruction GOTO ne seront pas expliqués en détail ici. Cependant, il n'y a pas de déclaration GOTO évidente dans JavaScript, mais à partir des instructions de rupture et des instructions de poursuite, il n'est pas difficile de trouver l'ombre de Goto en JavaScript.
En effet, les instructions de rupture et les instructions de poursuite permettent l'acceptation d'un nom d'étiquette défini pour la redirection de code.
Jetons un coup d'œil à l'exemple de code fourni par MDN.
La copie de code est la suivante:
var i, j;
LOOP1:
pour (i = 0; i <3; i ++) {// La première instruction est étiquetée "Loop1"
Loop2:
pour (j = 0; j <3; j ++) {// la seconde pour l'instruction est étiquetée "Loop2"
if (i == 1 && j == 1) {
Continuer Loop1;
} autre {
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, des boucles à deux couches sont implémentées et une étiquette est définie à l'extérieur de chaque boucle, qui est utilisée pour appeler l'instruction de poursuite ultérieure.
La première couche de boucle est dans l'étiquette de Loop1, c'est-à-dire que dans le programme ultérieur, si l'étiquette Loop1 est sélectionnée dans l'instruction Continuer ou Break, la boucle la plus externe se brisera.
La deuxième boucle de couche est dans l'étiquette de Loop2 dans la boucle de niveau supérieur. Si l'étiquette LOOP2 est sélectionnée dans l'instruction Continuer ou Break, elle reviendra au corps de boucle 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 qu'un système logique très complexe puisse être construit. Pour le dire franchement, il y a beaucoup de déclarations Goto dans le noyau Linux. Quant à savoir pourquoi vous entendez encore souvent des remarques comme les déclarations GOTO, il suffit de les rechercher sur Google vous-même.
5. Boucle avancée
5.1 Développez la boucle
Regardons d'abord les deux pièces de code et devinons lesquelles a de meilleures performances.
La copie de code est la suivante:
// Installation
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", "Data", "Data", "Data", "Data", "Data", "Data"]
]]
Processus de fonction (item) {
// faire quelque chose avec l'article
}
// Cas 1
pour (var i = array.length - 1; i> = 0; i--) {
pour (var j = array [i] .length - 1; j> = 0; i--) {
processus (array [i] [j]);
}
}
// Cas 2
for (var i = array.length - 1; i> = 0; i = i - 4) {
pour (var j = array [i] .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]);
}
pour (var j = array [i - 1] .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]);
}
pour (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]);
processus (array [i] [j - 5]);
}
pour (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]);
}
}
J'ai besoin de passer par tous les éléments du sous-réseau dans le tableau. Il existe deux solutions, l'une est la méthode que nous utilisons habituellement et l'autre consiste à étendre la tâche de boucle. La réponse est que le cas 2 fonctionne mieux, car tous les jugements d'exécution entre les 6 éléments sont supprimés, ce qui est naturellement plus rapide que d'habitude.
Ici, nous jetons un coup d'œil à une solution plus puissante. Si un lien commercial doit être traité de manière itérative sur un grand ensemble de données et que le volume de données ne changera pas par rapport au début de l'itération, vous pouvez envisager d'utiliser une technologie appelée dispositif DUFF. Cette technologie est nommée d'après son créateur Tom Duff, qui a d'abord été mis en œuvre dans la langue C. Plus tard, Jeff Greenberg l'a porté sur JavaScript et l'a modifié via Andrew b. King et a proposé une version plus efficace.
La copie de code est la suivante:
// Crédit: accélérez votre site (New Riders, 2003)
var iterations = math.floor (valeurs.length / 8);
var restant = valeurs.length% 8;
var i = 0;
if (restes> 0) {
faire {
processus (valeurs [i ++]);
} while (--leftOver> 0);
}
faire {
processus (valeurs [i ++]);
processus (valeurs [i ++]);
processus (valeurs [i ++]);
processus (valeurs [i ++]);
processus (valeurs [i ++]);
processus (valeurs [i ++]);
processus (valeurs [i ++]);
processus (valeurs [i ++]);
} while (--iterations> 0);
Le principe de travail de cette technique consiste à calculer la longueur des valeurs divisée par 8 pour obtenir le nombre d'itérations qui doivent être itérées, puis utiliser la fonction math.floor () pour garantir que le résultat est un entier, puis calculer le nombre qui ne peut pas être divisible par 8, et traiter ces éléments séparément, puis 8 sont une seule extension à elle.
J'ai emballé cet appareil et j'ai obtenu une API avec une saveur asynchrone.
La copie de code est la suivante:
fonction duff (tableau, mappeur) {
var n = math.floor (array.length / 8);
var l = array.length% 8;
var i = 0;
if (l> 0) {
faire {
Mappeur (tableau [i ++]);
} while (--i> 0);
}
faire {
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
Mappeur (tableau [i ++]);
} while (--n> 0);
}
Duff ([...], fonction (item) {
// ...
});
Voici un ensemble de tests de performance et de résultats pour les trois solutions itératives ci-dessus. http://jsperf.com/spreded-loop
5.2 Boucle non native
Dans tout langage de programmation, les boucles peuvent être implémentées non seulement indirectement d'autres manières, mais aussi d'autres manières.
Prenons d'abord un contenu des mathématiques du secondaire - la formule générale des séquences.
La copie de code est la suivante:
Basique
A [1] = 1
a [n] = 2 * a [n - 1] + 1
donc
a [n] + 1 = 2 * a [n - 1] + 2
= 2 * (a [n - 1] + 1)
(a [n] + 1) / (a [n - 1] + 1) = 2
Alors
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 devinez probablement de quoi nous allons discuter. Oui, nous pouvons également implémenter des boucles en utilisant la récursivité.
La récursivité est une méthode d'application très importante en mathématiques et en informatique, qui fait référence à une fonction qui s'appelle lorsqu'elle est utilisée.
Dans la communauté Node.js, Recursion est utilisée pour mettre en œuvre une technologie très importante: la technologie du middleware. Il s'agit d'une nouvelle version du code d'implémentation middleware dans WebJS qui n'a pas encore été publiée.
La copie de code est la suivante:
/ **
* Méthode d'exécution de Middlewares
* @param {String} URL Current Demande URL
* @param {objet} Req l'objet de demande
* @param {objet} Res l'objet de réponse
* @param {fonction} Rappel complet
* @return {fonction} le serveur
* /
server.runmiddlewares = fonction (url, req, res, out) {
var index = -1;
var middlewares = this._usingmiddlewares;
// Exécutez le middleware suivant s'il existe
fonction suivant (err) {
index ++;
// middleware actuel
var curr = middlewares [index];
if (curr) {
var check = new regexp (curr.Route);
// Vérifiez l'itinéraire
if (check.test (url)) {
essayer {
fonction ultérieurement () {
Debug («Un middleware dit qu'il doit être plus tard sur% s», URL);
// Les dépendances ne le font pas pour le moment
if (middlewares.indexof (curr)! == Middlewares.length - 1) {
_Later (curr);
indice--;
suivant();
} autre {
Debug («une dépendance des middleware mal»);
// ce middleware ne peut pas fonctionner
dehors();
}
}
// Exécutez le middleware
if (utils.isfunc (curr.handler)) {
// Fonction de middleware normale
curr.handler (req, res, suivant, plus tard);
} else if (utils.isobject (curr.handler) && utils.isfunc (curr.handler.emit)) {
// objet serveur
curr.handler.emit ('requête', req, res, suivant, plus tard);
} autre {
// Il y a quelque chose qui ne va pas dans le middleware
suivant();
}
} catch (err) {
suivant();
}
} autre {
suivant();
}
} autre {
// à l'étape suivante du pipeline
dehors();
}
}
// Si le middleware dépend des autres moyens de middle,
// il peut le laisser plus tard
fonction _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
suivant();
retourner ceci;
};
Bien que ce code soit dur et compliqué, il sera beaucoup plus clair si nous le simplifions.
La copie de code est la suivante:
server.runmiddlewares = fonction (url, req, res, out) {
var index = -1;
var middlewares = this._usingmiddlewares;
// Exécutez le middleware suivant s'il existe
fonction suivant (err) {
index ++;
// middleware actuel
var curr = middlewares [index];
if (curr) {
var check = new regexp (curr.Route);
// Vérifiez l'itinéraire
if (check.test (url)) {
// exécuter le middleware actuel
curr.handler (req, res, suivant);
} autre {
suivant();
}
} autre {
// à l'étape suivante du pipeline
dehors();
}
}
// Premier middleware
suivant();
retourner ceci;
};
La raison pour laquelle la récursivité peut être utilisée dans la mise en œuvre du système middleware est que la récursivité est la méthode la plus appropriée de réponse de flux de programme dans Node.js.
Dans ce code d'implémentation du middleware, ce._usingMiddlewares est un tableau de boucle, la fonction suivant () est un corps de boucle, où Check.test (URL) est la condition de jugement d'exécution, et le code de traitement de boucle est le premier compteur d'index dans le corps de boucle pour augmenter de 1 et la fonction suivante.