Los bucles son uno de los mecanismos más importantes en todos los lenguajes de programación, y los bucles no están abiertos en casi cualquier programa de computadora con importancia práctica (clasificación, consulta, etc.). Looping también es una parte muy problemática de la optimización del programa. A menudo necesitamos optimizar constantemente la complejidad del programa, pero estamos enredados en la elección entre complejidad del tiempo y complejidad del espacio debido al bucle.
En JavaScript, hay 3 bucles nativos, para () {}, while () {} y do {} while (), y los más utilizados son para () {}.
Sin embargo, es el bucle más probable que los ingenieros de JavaScript ignoran al optimizar los programas.
Primero revisemos el conocimiento básico de para.
La sintaxis de JavaScript se hereda del lenguaje C, y hay dos formas de usar la sintaxis básica de los bucles.
1. Matriz de bucle
Sintaxis básica de bucle
La copia del código es la siguiente:
para ( / * inicialización * /2 / * condición de juicio * /2 / * procesamiento de bucle * /) {
// ... Código lógico
}
Explicaremos en detalle con un código de instancia.
La copia del código es la siguiente:
varilla var = [1, 2, 3, 4, 5];
var sum = 0;
para (var i = 0, len = array.length; i <len; ++ i) {
sum += array [i];
}
console.log ('La suma de los elementos de la matriz es %d.', suma);
// => La suma de los elementos de la matriz es 15.
En este código, primero definimos e inicializamos una matriz que almacena los elementos para acumularse y una variable de configuración de suma. A continuación, comenzamos el bucle. En el código de inicialización de esto para el bucle, también definimos e inicializamos dos variables: I (contador) y len (alias de longitud de matriz de bucle). Cuando es menos que LEN, se establece la condición de bucle y se ejecuta el código lógico; Después de ejecutar cada código lógico, me incrementaré por 1.
En el código lógico del bucle, agregamos los términos de matriz del bucle actual a la variable de suma.
Este ciclo está representado por el diagrama de flujo de la siguiente manera:
A partir de este diagrama de flujo, no es difícil encontrar que el cuerpo de bucle real en el programa no solo contiene nuestro código lógico, sino que también incluye el juicio de ejecución y el procesamiento de bucle que implementa el bucle en sí.
De esta manera, nuestras ideas de optimización serán claras y podemos optimizar desde cuatro aspectos.
1. Código de inicialización antes del cuerpo del bucle
2. Condiciones de juicio de ejecución en el cuerpo del bucle
3. Código lógico
4. Código de procesamiento después del código lógico
PD: Existe una relación importante entre el primer punto y el segundo punto.
1.1 Optimizar el código de inicialización y las condiciones de juicio de ejecución
Primero echemos un vistazo a un código con el que todos están muy familiarizados.
La copia del código es la siguiente:
// ¡equivocado!
para (var i = 02 i <list.length2 ++ i) {
// ... Código lógico
}
Creo que la mayoría de los ingenieros que escriben JavaScript todavía están usando este método de bucle aparentemente normal, pero ¿por qué digo que está mal aquí?
Detiramos todo en este bucle y echemos un vistazo:
1. Inicializar el código: este bucle solo define e inicializa una variable de contador.
2. Condición de juicio de ejecución: es cierto cuando el contador es menor que la longitud de la lista.
3. Código de procesamiento: el contador se incrementa en 1.
Revisemos el diagrama de flujo anterior y descubramos si hay algo de malo en ello.
El cuerpo de bucle real no solo tiene nuestro código lógico, sino que también incluye el juicio de ejecución y el código de procesamiento que implementa el bucle en sí. En otras palabras, la condición de juicio i <list.length debe ejecutarse antes de cada bucle. En JavaScript, se requiere una consulta al leer las propiedades o métodos de un objeto.
Parece que entiendes algo, ¿verdad? Hay dos operaciones en esta condición de juicio: 1. Consulte el atributo de longitud de la matriz de la lista; 2. Compare los tamaños de i y list.length.
Suponiendo que la matriz de lista contiene n elementos, el programa debe realizar operaciones 2n en el juicio de ejecución de este bucle.
Si cambiamos el código a esto:
La copia del código es la siguiente:
// Bien
para (var i = 0, len = list.length; i <len; ++ i) {
// ...
}
En este código mejorado, agregamos una definición e inicializamos una variable LEN para almacenar el valor de la lista. Longitud en el código de inicialización antes de la ejecución del cuerpo del bucle (el contenido relevante sobre variables, expresiones, punteros y valores se discutirá en el segundo artículo). De esta manera, no necesitamos consultar la matriz de la lista nuevamente en el juicio de ejecución en el cuerpo del bucle, y el operando es la mitad del original.
En los pasos anteriores, hemos mejorado la complejidad del tiempo del algoritmo y ¿cómo debemos hacerlo si queremos continuar optimizando la complejidad del espacio? Si su código lógico no está limitado por el orden de bucle, puede probar el siguiente método de optimización.
La copia del código es la siguiente:
for (var i = list.length -1; i> = 0; --i) {
// ...
}
Este código se adelanta invirtiendo el orden de bucle, comenzando con el último subíndice de elementos (list.length - 1). Para reducir el número de variables requeridas para el bucle a 1, y en el juicio de ejecución, se reduce el número de consultas variables y se reduce el tiempo dedicado antes de ejecutar la instrucción de la CPU.
1.2 Optimización del código lógico
En un bucle, obtenemos el elemento de matriz actual del bucle, naturalmente para hacer algunas operaciones en él o usarlo, lo que inevitablemente conduce a varias llamadas al elemento.
La copia del código es la siguiente:
Var Array = [
{Nombre: 'Will Wen Gunn', Tipo: 'Hentai'},
{Nombre: 'Vill Lin', Tipo: 'Moegril'}
];
for (var i = array.length -1; i> = 0; --i) {
console.log ('Nombre: %S', Array [i] .name);
console.log ('él/ella es un (n) %s', matriz [i] .type);
console.log ('/r/n');
}
/*=>
Nombre: Vill Lin
Él/ella es un (n) moegril
Nombre: Will Wen Gunn
Él/ella es un (n) hentai
*/
En este código, el programa debe consultar el nombre y el tipo de atributos de cada elemento de matriz. Si la matriz tiene n elementos, el programa realizará consultas de objetos 4n.
La copia del código es la siguiente:
1. Array [i]
2. Array [i] .Name
3. Array [i]
4. Array [i] .Type
Creo que debe haber pensado en una solución en este momento, es decir, asignar el valor del elemento de matriz actual a una variable y luego usarla en el código lógico.
La copia del código es la siguiente:
Var Array = [
{Nombre: 'Will Wen Gunn', Tipo: 'Hentai'},
{Nombre: 'Vill Lin', Tipo: 'Moegril'}
];
VAR Person = NULL;
for (var i = array.length -1; i> = 0 && (persona = array [i]); --i) {
console.log ('Nombre: %s', persona.name);
console.log ('él/ella es un (n) %s', persona.type);
console.log ('/r/n');
}
persona = nulo;
Esto se ve mucho más hermoso.
La copia del código es la siguiente:
1. Array [i] => Var Person
2. Person.name
3. Persona type
Es un poco como el foreach en emcascript5, pero la diferencia entre los dos es enorme, por lo que no lo explicaré aquí.
PD: Gracias por su corrección. Después de los experimentos, descubrí que si los elementos en la matriz se definen directamente con valores de aprobación, el valor obtenido en el bucle debe ser un valor, no un puntero. Entonces, ya sea que defina expresiones o variables, habrá solicitudes adicionales de espacio de memoria.
1.3 Optimizar el código de procesamiento
De hecho, no hay mucho para optimizar el código de procesamiento en el cuerpo del bucle, y el contador I es suficiente para aumentar el 1 por sí solo.
PD: Si tiene buenas sugerencias o métodos, proporcione. :)
2. Objeto circular (objeto)
En JavaScript, también puede atravesar las propiedades y métodos del objeto. Cabe señalar que el bucle for no puede pasar por el tipo de envoltura al que pertenece el objeto o las propiedades y métodos del prototipo en el constructor.
La sintaxis es más simple que las matrices de bucle.
La copia del código es la siguiente:
for (/* inicialize*/ var key en objeto) {
// ... Código lógico
}
A menudo usamos este método para operar en objetos.
La copia del código es la siguiente:
Var Person = {
'Nombre': 'Will Wen Gunn',
'tipo': 'hentai',
'habilidad': ['programación', 'fotografía', 'hablar', 'etc']
};
para (clave var en persona) {
valor = persona [clave];
// Si el valor es una matriz, conviértalo en una cadena
if (instancia de valor de matriz) {
value = value.Join (',');
}
console.log (' %s: %s', clave, valor);
}
/*=>
Nombre: Will Wen Gunn
Tipo: hentai
Habilidad: programación, fotografía, habla, etc.
*/
Si ha usado MongoDB, definitivamente estará familiarizado con su mecanismo de consulta. Debido a que el mecanismo de consulta de MongoDB es como el alma de su API, el método de operación de cuajada flexible ha ganado a MongoDB mucha popularidad e impulso de desarrollo.
En la implementación de la API de Mongo de NANODB, la implementación de consultas utiliza objetos de bucle a gran escala.
La copia del código es la siguiente:
var mydb = nano.db ('mydb');
var mycoll = mydb.collection ('mycoll');
var _cursor = mycoll.find ({
Tipo: 'Repo',
Idioma: 'JavaScript'
});
_cursor
.clasificar({
Estrella: 1
})
.toarray (function (err, filas) {
if (err)
return console.error (err);
console.log (filas);
});
Lo que necesitamos para optimizar no es el bucle en sí, sino la optimización de los objetos por los que debe pasar.
Por ejemplo, la clase de nanocolección en Nanodb parece una matriz, que contiene todos los elementos u objetos, y usa la ID del elemento como clave y luego almacena los elementos.
Pero este no es el caso. Los estudiantes que han usado subrayado deben conocer el método _.invert. Esta es una forma bastante interesante de revertir las teclas y los valores del objeto que se está pasando.
La copia del código es la siguiente:
Var Person = {
'Nombre': 'Will Wen Gunn',
'tipo': 'hentai'
};
var _inverted = _.invert (persona);
console.log (_Inverted);
/*=>
{
'Will Wen Gunn': 'Nombre',
'hentai': 'tipo'
}
*/
Si necesita usar un objeto de bucle para consultar los valores de ciertas propiedades del objeto, puede probar el siguiente método.
La copia del código es la siguiente:
Var Person = {
'Nombre': 'Will Wen Gunn',
'tipo': 'hentai'
};
var name = 'Will Wen Gunn';
var _inverted = _.invert (persona);
if (_Inverted [name] === 'Nombre') {
console.log ('¡Atrapado!');
}
// => ¡atrapado!
Sin embargo, no hay mucha optimización para usar para la consulta de objetos, y todo debe basarse en las necesidades reales. : pag
A continuación, miramos los otros dos bucles, while () {} y hacemos {} while (). Creo que cualquier amigo que haya recibido un curso de informática estará familiarizado con estos dos ciclos. La única diferencia entre ellos es el orden lógico de ejecución del cuerpo del bucle.
La orden de ejecución de WHIEN () {} es similar a la de for () {}. Los juicios de ejecución se realizan antes del código lógico, pero se omite el código de inicialización y procesamiento.
Cuando se da una condición, el código lógico se ejecuta hasta que la condición ya no se mantenga.
La copia del código es la siguiente:
var sum = 0;
while (sum <10) {
suma + = suma + 1;
}
console.log (suma);
// => 15
do {} while () pone el juicio de ejecución después del código lógico, que significa "muerto primero y luego jugar".
La copia del código es la siguiente:
var sum = 0;
hacer {
suma + = suma + 1;
} while (suma <10);
console.log (suma);
// => 15
While () {} y do {} while () tampoco requiere un contador, pero use ciertas condiciones para determinar si ejecutar o continuar ejecutando un código lógico.
3. While () {} y do {} while ()
while () {} y do {} while () se usan principalmente en la lógica de negocios, y una serie de operaciones se ejecutan continuamente para lograr un cierto propósito, como las colas de tareas.
Pero estos dos bucles son peligrosos porque solo están controlados por condiciones de ejecución de forma predeterminada. Si no hay impacto en el juicio de ejecución en el código lógico, se producirá un bucle muerto.
La copia del código es la siguiente:
var suma = 02
// ¡advertencia!
while (sum <10) {
suma = 1 + 12
}
Dicho código no es diferente de while (verdadero) {}, por lo que antes de su uso, es necesario aclarar las condiciones de ejecución y cómo afectar las condiciones de ejecución.
4. Haga un buen uso de las declaraciones de control de bucle
Creo que todos los ingenieros de JavaScript han usado declaraciones de descanso, pero las declaraciones continuas rara vez se usan raramente. De hecho, hay muchos excelentes proyectos de código abierto de JavaScript que se pueden encontrar.
Para resolver la función de la declaración continuar, echemos un vistazo al código de ejemplo primero
La copia del código es la siguiente:
// servidor de transmisión node.js
var net = require ('net');
var util = require ('util');
var BroadcastServer = net.createServer ();
// tienda de clientes
broadcastServer.clients = [];
// Método de transmisión de clientes
net.socket.prototype.broadcast = function (msg) {
var clientes = broadcastServer.clients;
// Obtener el subíndice del cliente de transmisión en el centralizado
Var index = clients.indexof (this);
for (var i = clients.length -1; i> = 0; --i) {
if (i === index) {
// Si es un cliente de transmisión, el cuerpo de bucle actual se terminará
continuar;
}
CurrClient = clientes [i];
if (! CurrClient.destroyed) {
CurrClient.Write (
util.Format (
'/r [echo cliente %s: %d] %s/ninput:',,
CurrClient.remoteaddress, CurrClient.remoteport, MSG)
);
}
}
};
// Un nuevo cliente conectado
broadcastServer.on ('Connection', function (Client) {
broadcastServer.clients.push (cliente);
// Bienvenido
Client.Write ('[Servidor de transmisión] ¡Bienvenido!/Ninput:');
Client.Broadcast (Cliente, 'Junto!');
// Manejo de mensajes
client.on ('data', function (msg) {
Client.Broadcast (MSG);
Client.write ('/rinput:');
});
// Mango de desconexión
client.on ('end', function () {
Client.Broadcast ('Left!');
})
});
// Unir
broadcastServer.listen (8080, function () {
console.log ('Broadcast Server Bound.');
});
Este código implementa un servidor de transmisión basado en el módulo de red Node.js. En el método de transmisión, utilizamos la declaración Continuar para implementar todos los clientes conectados que hayan establecido conexiones excepto el cliente de transmisión.
El contenido del código es bastante simple. Cuando un cliente necesita transmitir a otros clientes, se llama al método de transmisión del objeto del cliente correspondiente al cliente. En el método de transmisión, el programa primero obtendrá el subíndice de posición del cliente actual en la colección de socket del cliente en caché, y luego recorrerá todos los sockets del cliente. Cuando el contador de bucle alcanza el subíndice de posición que obtuvo antes, se omitirá el código lógico en el cuerpo de bucle actual y el siguiente bucle continuará.
Creo que los ingenieros que han aprendido el lenguaje C/C ++ obtendrán este consejo de varios lugares: "No uses las declaraciones de GOTO".
Esta declaración de GOTO "notoria" es en realidad un controlador de flujo de código, y los detalles de la declaración GOTO no se explicarán en detalle aquí. Sin embargo, no hay una declaración obvia en JavaScript, pero de las declaraciones de descanso y las declaraciones continuar, no es difícil encontrar la sombra de GOTO en JavaScript.
Esto se debe a que las declaraciones de descanso y las declaraciones de continuo permiten la aceptación de un nombre de etiqueta definido para la redirección del código.
Echemos un vistazo al código de ejemplo proporcionado por MDN.
La copia del código es la siguiente:
var i, j;
bucle1:
para (i = 0; i <3; i ++) {// La primera para la declaración está etiquetada como "Loop1"
Loop2:
para (j = 0; j <3; j ++) {// El segundo para la declaración está etiquetado como "loop2"
if (i == 1 && j == 1) {
continuar loop1;
} demás {
console.log ("i =" + i + ", j =" + j);
}
}
}
// La salida es:
// "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"
// Observe cómo omita "i = 1, j = 1" y "i = 1, j = 2"
En este código de ejemplo, se implementan bucles de dos capas y se define una etiqueta fuera de cada bucle, que se utiliza para llamar a la declaración continua posterior.
La primera capa de bucle está en la etiqueta de Loop1, es decir, en el programa posterior, si la etiqueta Loop1 se selecciona en la instrucción continua o la declaración de interrupción, el bucle más externo se romperá.
El segundo bucle de capa está en la etiqueta de Loop2 en el bucle de nivel superior. Si la etiqueta Loop2 se selecciona en la instrucción Continuar o Break, volverá al cuerpo de bucle del bucle de nivel superior.
Al usar declaraciones de control de bucle, podemos interferir con el juicio de ejecución de bucle original, de modo que se pueda construir un sistema lógico muy complejo. Para decirlo sin rodeos, hay muchas declaraciones de GOTO en Linux Kernel. En cuanto a por qué todavía escuchas comentarios como las declaraciones de GOTO, solo busca en Google tú mismo.
5. Bucle avanzado
5.1 Expanda el bucle
Primero veamos las dos piezas de código, y adivinemos cuál tiene un mejor rendimiento.
La copia del código es la siguiente:
// Configuración
Var Array = [
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"],
["Datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos", "datos"]]
];
proceso de función (elemento) {
// hacer algo con el artículo
}
// Caso 1
para (var i = array.length-1; i> = 0; i--) {
for (var j = array [i] .length-1; j> = 0; i--) {
proceso (matriz [i] [j]);
}
}
// Caso 2
para (var i = array.length - 1; i> = 0; i = i - 4) {
for (var j = array [i] .length - 1; j> = 0; j = j - 6) {
proceso (matriz [i] [j]);
proceso (matriz [i] [j - 1]);
proceso (matriz [i] [j - 2]);
proceso (matriz [i] [j - 3]);
proceso (matriz [i] [j - 4]);
proceso (matriz [i] [j - 5]);
}
para (var j = array [i - 1] .length - 1; j> = 0; j = j - 6) {
proceso (matriz [i] [j]);
proceso (matriz [i] [j - 1]);
proceso (matriz [i] [j - 2]);
proceso (matriz [i] [j - 3]);
proceso (matriz [i] [j - 4]);
proceso (matriz [i] [j - 5]);
}
para (var j = array [i - 2] .length - 1; j> = 0; j = j - 6) {
proceso (matriz [i] [j]);
proceso (matriz [i] [j - 1]);
proceso (matriz [i] [j - 2]);
proceso (matriz [i] [j - 3]);
proceso (matriz [i] [j - 4]);
proceso (matriz [i] [j - 5]);
}
para (var j = array [i - 3] .length - 1; j> = 0; j = j - 6) {
proceso (matriz [i] [j]);
proceso (matriz [i] [j - 1]);
proceso (matriz [i] [j - 2]);
proceso (matriz [i] [j - 3]);
proceso (matriz [i] [j - 4]);
proceso (matriz [i] [j - 5]);
}
}
Necesito pasar por todos los elementos de la subarray en la matriz. Hay dos soluciones, una es el método que generalmente usamos, y el otro es expandir la tarea de bucle. La respuesta es que el caso 2 funciona mejor, porque se eliminan todos los juicios de ejecución entre cada 6 elementos, que es naturalmente más rápido de lo habitual.
Aquí echamos un vistazo a una solución más poderosa. Si un enlace comercial debe procesarse iterativamente en un gran conjunto de datos, y el volumen de datos no cambiará desde el comienzo de la iteración, entonces puede considerar usar una tecnología llamada dispositivo DUFF. Esta tecnología lleva el nombre de su creador Tom Duff, que se implementó por primera vez en el lenguaje C. Más tarde, Jeff Greenberg lo portó a JavaScript y lo modificó a través de Andrew b. rey y propuso una versión más eficiente.
La copia del código es la siguiente:
// Crédito: acelere su sitio (New Riders, 2003)
var iterations = Math.floor (valores.length / 8);
VAR sobrante = valores. Longitud % 8;
var i = 0;
if (sobrante> 0) {
hacer {
proceso (valores [i ++]);
} while (--leftover> 0);
}
hacer {
proceso (valores [i ++]);
proceso (valores [i ++]);
proceso (valores [i ++]);
proceso (valores [i ++]);
proceso (valores [i ++]);
proceso (valores [i ++]);
proceso (valores [i ++]);
proceso (valores [i ++]);
} while (--iterations> 0);
El principio de funcionamiento de esta técnica es calcular la longitud de los valores divididos por 8 para obtener el número de iteraciones que deben ser iteradas, y usar la función Math.floor () para garantizar que el resultado sea un entero, y luego calcule el número que no puede ser divisible por 8 y procesa estos elementos por separado, y luego 8 es una sola expansión para iterar.
Empaqué este dispositivo y obtuve una API con un sabor asíncrono.
La copia del código es la siguiente:
function duff (array, mapper) {
var n = math.floor (array.length / 8);
var l = array.length % 8;
var i = 0;
if (l> 0) {
hacer {
mapper (matriz [i ++]);
} while (--i> 0);
}
hacer {
mapper (matriz [i ++]);
mapper (matriz [i ++]);
mapper (matriz [i ++]);
mapper (matriz [i ++]);
mapper (matriz [i ++]);
mapper (matriz [i ++]);
mapper (matriz [i ++]);
mapper (matriz [i ++]);
} while (--n> 0);
}
duff ([...], function (elemento) {
// ...
});
Aquí hay un conjunto de pruebas de rendimiento y resultados para las tres soluciones iterativas anteriores. http://jsperf.com/spreed-loop
5.2 bucle no nativo
En cualquier lenguaje de programación, los bucles se pueden implementar no solo indirectamente de otras maneras, sino también de otras maneras.
Primero revisemos algún contenido de las matemáticas de la escuela secundaria: la fórmula general de las secuencias.
La copia del código es la siguiente:
Básico
a [1] = 1
a [n] = 2 * a [n - 1] + 1
entonces
a [n] + 1 = 2 * a [n - 1] + 2
= 2 * (a [n - 1] + 1)
(a [n] + 1) / (a [n - 1] + 1) = 2
Entonces
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
Después de leer el cálculo simple anterior, probablemente adivine lo que vamos a discutir. Sí, también podemos implementar bucles utilizando la recursión.
La recursión es un método de aplicación muy importante en matemáticas e informática, que se refiere a una función que se llama a sí misma cuando se usa.
En la comunidad Node.js, la recursión se utiliza para implementar una tecnología muy importante: la tecnología de middleware. Esta es una nueva versión del código de implementación de middleware en WebJS que aún no se ha publicado.
La copia del código es la siguiente:
/**
* Método de ejecución de MiddleWares
* @param {string} URL URL de solicitud actual
* @param {objeto} req el objeto de solicitud
* @param {objeto} res el objeto de respuesta
* @param {function} Out Complete Callback
* @return {function} el servidor
*/
server.runmiddlewares = function (url, req, res, out) {
Var index = -1;
var middleWares = this._UsingMiddleWares;
// Ejecute el siguiente middleware si existe
function next (err) {
índice ++;
// middleware actual
var curr = middleWares [índice];
if (Curr) {
var check = new Regexp (Curr.Rutee);
// Verifique la ruta
if (check.test (url)) {
intentar {
función luego () {
debug ('un middleware dice que debe estar más tarde en %s', url);
// Las dependencias no lo hacen ahora mismo
if (middleWares.Indexof (Curr)! == MiddleWares.length - 1) {
_later (Curr);
índice--;
próximo();
} demás {
depurar ('Un middleware Dependences incorrecto');
// Este middleware no puede ejecutarse
afuera();
}
}
// Ejecute el middleware
if (utils.isfunc (Curr.handler)) {
// función de middleware normal
Curr.handler (req, res, siguiente, más tarde);
} else if (utils.isobject (curr.handler) && utils.isfunc (curr.handler.emit)) {
// Objeto del servidor
curr.handler.emit ('solicitud', req, res, siguiente, más tarde);
} demás {
// Hay algo mal en el middleware
próximo();
}
} catch (err) {
próximo();
}
} demás {
próximo();
}
} demás {
// al siguiente paso de la tubería
afuera();
}
}
// Si el middleware depende de otros artículos intermedios,
// puede dejar que se ejecute más tarde
función _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;
}
// Primer middleware
próximo();
devolver esto;
};
Aunque este código se ve duro y complicado, será mucho más claro si lo simplificamos.
La copia del código es la siguiente:
server.runmiddlewares = function (url, req, res, out) {
Var index = -1;
var middleWares = this._UsingMiddleWares;
// Ejecute el siguiente middleware si existe
function next (err) {
índice ++;
// middleware actual
var curr = middleWares [índice];
if (Curr) {
var check = new Regexp (Curr.Rutee);
// Verifique la ruta
if (check.test (url)) {
// Ejecute el middleware actual
Curr.handler (req, res, siguiente);
} demás {
próximo();
}
} demás {
// al siguiente paso de la tubería
afuera();
}
}
// Primer middleware
próximo();
devolver esto;
};
La razón por la cual se puede utilizar la recursión en la implementación del sistema de middleware es que la recursión es el método más adecuado de respuesta al flujo del programa en Node.js.
En este código de implementación de middleware, este._USINGMIDDDEDEWARES es una matriz de bucle, la función Next () es un cuerpo de bucle, donde check.test (url) es la condición de juicio de ejecución, y el código de procesamiento de bucle es el primer contador de índice en el cuerpo del bucle para incrementar por 1 y la siguiente función en sí.