Os loops são um dos mecanismos mais importantes em todas as linguagens de programação, e os loops não estão abertos em quase qualquer programa de computador com significado prático (classificação, consulta etc.). O loop também é uma parte muito problemática da otimização do programa. Geralmente, precisamos otimizar constantemente a complexidade do programa, mas estamos enredados na escolha entre a complexidade do tempo e a complexidade do espaço devido ao loop.
No JavaScript, existem 3 loops nativos, para () {}, while () {} e fazer {} while (), e os mais usados são para () {}.
No entanto, pois é o loop mais provável que os engenheiros de JavaScript ignoram ao otimizar os programas.
Vamos primeiro revisar o conhecimento básico de para.
A sintaxe do JavaScript é herdada do idioma C e há duas maneiras de usar a sintaxe básica de loops.
1. Array em loop
Sintaxe básica de para loop
A cópia do código é a seguinte:
para ( / * inicialização * /2 / * condição de julgamento * /2 / * Processamento de loop * /) {
// ... código lógico
}
Explicaremos em detalhes com um código de instância.
A cópia do código é a seguinte:
var Array = [1, 2, 3, 4, 5];
var sum = 0;
for (var i = 0, len = array.length; i <len; ++ i) {
soma += matriz [i];
}
console.log ('a soma dos itens da matriz/é %d.', soma);
// => A soma dos itens da matriz é 15.
Neste código, primeiro definimos e inicializamos uma matriz que armazena os itens a serem acumulados e uma variável de modelagem de soma. Em seguida, começamos o loop. No código de inicialização disso para loop, também definimos e inicializamos duas variáveis: i (contador) e len (alias do comprimento da matriz de loop). Quando eu é menor que Len, a condição do loop é estabelecida e o código lógico é executado; Depois que cada código lógico for executado, serei incrementado em 1.
No código lógico do loop, adicionamos os termos da matriz do loop atual à variável SUM.
Este ciclo é representado pelo fluxograma da seguinte forma:
A partir desse fluxograma, não é difícil descobrir que o corpo do loop real no programa não apenas contém nosso código lógico, mas também inclui o julgamento da execução e o processamento de loop que implementa o próprio loop.
Dessa forma, nossas idéias de otimização serão claras e podemos otimizar de quatro aspectos.
1. Código de inicialização antes do corpo do loop
2. Condições de julgamento de execução no corpo do loop
3. Código lógico
4. Código de processamento após código lógico
PS: Existe uma relação importante entre o primeiro ponto e o segundo ponto.
1.1 Otimize o código de inicialização e as condições de julgamento de execução
Vamos primeiro dar uma olhada em um pedaço de código com o qual todos estão muito familiarizados.
A cópia do código é a seguinte:
// errado!
para (var i = 02 i <list.length2 ++ i) {
// ... código lógico
}
Acredito que a maioria dos engenheiros que escrevem JavaScript ainda estão usando esse método de loop aparentemente normal, mas por que eu digo que está errado aqui?
Vamos desmontar tudo neste loop e dar uma olhada:
1. Inicialize o código - esse loop define e inicializa uma variável contador.
2. Condição de julgamento de execução - é verdade quando o contador é menor que o comprimento da lista.
3. Código de processamento - O contador é incrementado em 1.
Vamos revisar o fluxograma acima e descobrir se há algo de errado com ele?
O corpo real do loop não apenas tem nosso código lógico, mas também inclui o julgamento da execução e o código de processamento que implementa o próprio loop. Em outras palavras, a condição de julgamento i <list.length deve ser executada antes de cada loop. No JavaScript, é necessária uma consulta ao ler as propriedades ou métodos de um objeto.
Você parece entender algo, certo? Existem duas operações nessa condição de julgamento: 1. Consulta o atributo de comprimento da matriz da lista; 2. Compare os tamanhos de i e list.length.
Supondo que a matriz da lista contenha n elementos, o programa precisa executar operações 2N no julgamento da execução desse loop.
Se alterarmos o código para isso:
A cópia do código é a seguinte:
// Bem
for (var i = 0, len = list.length; i <len; ++ i) {
// ...
}
Neste código aprimorado, adicionamos uma definição e inicializamos uma variável LEN para armazenar o valor da lista. Comprimento no código de inicialização antes da execução do corpo do loop (o conteúdo relevante sobre variáveis, expressões, ponteiros e valores será discutido no segundo artigo). Dessa forma, não precisamos consultar a matriz da lista novamente no julgamento da execução no corpo do loop, e o operando é metade do original.
Nas etapas acima, melhoramos a complexidade do tempo do algoritmo e como devemos fazê -lo se queremos continuar otimizando a complexidade do espaço? Se o seu código lógico não estiver limitado pela ordem do loop, você poderá tentar o seguinte método de otimização.
A cópia do código é a seguinte:
for (var i = list.length -1; i> = 0; --i) {
// ...
}
Esse código é encaminhado invertendo a ordem do loop, começando com o último subscrito do elemento (list.length - 1). Para reduzir o número de variáveis necessárias para o loop para 1 e, no julgamento da execução, o número de consultas variáveis é reduzido e o tempo gasto antes da execução da instrução da CPU é reduzido.
1.2 Otimizando o código lógico
Em um loop, obtemos o elemento atual da matriz do loop, naturalmente para fazer algumas operações nele ou usá -lo, o que inevitavelmente leva a várias chamadas para o elemento.
A cópia do código é a seguinte:
var Array = [
{Nome: 'Will Wen Gunn', Tipo: 'Hentai'},
{Nome: 'Vill Lin', Tipo: 'Moegril'}
];
for (var i = array.length -1; i> = 0; --i) {
console.log ('nome: %s', matriz [i] .name);
console.log ('ele/ela é (n) %s', matriz [i] .Type);
console.log ('/r/n');
}
/*=>
Nome: Vill Lin
Ele/ela é um (n) moegril
Nome: Wen Wen Gunn
Ele/ela é um (n) hentai
*/
Neste código, o programa precisa consultar os atributos de nome e tipo de cada elemento da matriz. Se a matriz tiver n elementos, o programa executará consultas de objeto 4N.
A cópia do código é a seguinte:
1. Array [i]
2. Array [i] .Nome
3. Array [i]
4. Array [i] .Type
Acredito que você deve ter pensado em uma solução neste momento, ou seja, atribuir o valor do elemento de matriz atual a uma variável e depois usá -la no código lógico.
A cópia do código é a seguinte:
var Array = [
{Nome: 'Will Wen Gunn', Tipo: 'Hentai'},
{Nome: 'Vill Lin', Tipo: 'Moegril'}
];
var pessoa = nulo;
for (var i = array.length -1; i> = 0 && (pessoa = array [i]); --i) {
console.log ('nome: %s', pessoa.name);
console.log ('ele/ela é (n) %s', pessoa.type);
console.log ('/r/n');
}
pessoa = nulo;
Isso parece muito mais bonito.
A cópia do código é a seguinte:
1. Array [i] => var pessoa
2. Pessoa.name
3. Pessoa.Type
É um pouco como o foreach no EMCSCRIPT5, mas a diferença entre os dois é enorme, então não vou explicar aqui.
PS: Obrigado pela sua correção. Após as experiências, descobri que, se os elementos da matriz forem definidos pela passagem diretamente, o valor obtido no loop deve ser um valor, não um ponteiro. Portanto, se você definir expressões ou variáveis, haverá solicitações adicionais de espaço de memória.
1.3 Otimize o código de processamento
De fato, não há muito para otimizar o código de processamento no corpo do loop, e o contador I é suficiente para aumentar o 1 por si só.
PS: Se você tiver boas sugestões ou métodos, forneça -os. :)
2. Objeto circular (objeto)
Em JavaScript, pois também pode atravessar as propriedades e métodos do objeto. Deve -se notar que o loop for não pode passar pelo tipo de embalagem ao qual o objeto pertence ou as propriedades e métodos do protótipo no construtor.
A sintaxe é mais simples que as matrizes em loop.
A cópia do código é a seguinte:
para (/* inicialize*/ var tecla no objeto) {
// ... código lógico
}
Muitas vezes usamos esse método para operar em objetos.
A cópia do código é a seguinte:
var pessoa = {
'Nome': 'Will Wen Gunn',
'tipo': 'hentai',
'Habilidade': ['programação', 'fotografia', 'falando', 'etc']
};
para (chave de var pessoalmente) {
valor = pessoa [chave];
// Se o valor for matriz, converta -o em uma string
if (instância do valor da matriz) {
value = value.Join (',');
}
console.log (' %s: %s', chave, valor);
}
/*=>
Nome: Wen Wen Gunn
Tipo: hentai
Habilidade: programação, fotografia, fala, etc
*/
Se você usou o MongoDB, definitivamente estará familiarizado com seu mecanismo de consulta. Como o mecanismo de consulta do MongoDB é como a alma de sua API, o método flexível de operação de coalhada ganhou muito o MongoDB.
Na implementação da API Mongo do NANODB, a implementação da consulta usa objetos de loop em larga escala.
A cópia do código é a seguinte:
var mydb = nano.db ('mydb');
var mycoll = mydb.collection ('mycoll');
var _cursor = mycoll.find ({
Tipo: 'repo',
Idioma: 'JavaScript'
});
_cursor
.organizar({
Estrela: 1
})
.toArray (function (err, linhas) {
se (err)
retornar console.error (err);
console.log (linhas);
});
O que precisamos otimizar não é o próprio loop, mas a otimização dos objetos que você precisa passar.
Por exemplo, a classe Nanocollection no Nanodb parece uma matriz, que contém todos os elementos ou objetos, e usa o ID do elemento como a chave e depois armazena os elementos.
Mas esse não é o caso. Os alunos que usaram o sublinhado devem conhecer o método _.invert. Esta é uma maneira bastante interessante de reverter as chaves e os valores do objeto que está sendo passado.
A cópia do código é a seguinte:
var pessoa = {
'Nome': 'Will Wen Gunn',
'tipo': 'hentai'
};
var _inverted = _.invert (pessoa);
console.log (_inverted);
/*=>
{
'Will Wen Gunn': 'Nome',
'Hentai': 'Type'
}
*/
Se você precisar usar um objeto de loop para consultar os valores de certas propriedades do objeto, poderá tentar o seguinte método.
A cópia do código é a seguinte:
var pessoa = {
'Nome': 'Will Wen Gunn',
'tipo': 'hentai'
};
var name = 'wen gunn';
var _inverted = _.invert (pessoa);
if (_inverted [nome] === 'nome') {
console.log ('capturado!');
}
// => capturado!
No entanto, não há muita otimização para usar para a consulta de objetos, e tudo precisa ser baseado nas necessidades reais. : p
Em seguida, olhamos para os outros dois loops, enquanto () {} e fazemos {} while (). Acredito que qualquer amigo que tenha recebido um curso de ciência da computação estará familiarizado com esses dois ciclos. A única diferença entre eles é a ordem lógica de execução do corpo do loop.
A ordem de execução de while () {} é semelhante à de for () {}. Os julgamentos de execução são realizados antes do código lógico, mas o código de inicialização e processamento é omitido.
Quando uma condição é fornecida, o código lógico é executado até que a condição não seja mais segurada.
A cópia do código é a seguinte:
var sum = 0;
while (soma <10) {
soma + = soma + 1;
}
console.log (soma);
// => 15
Do {} while () coloca o julgamento da execução após o código lógico, que significa "morto primeiro e depois reproduzir".
A cópia do código é a seguinte:
var sum = 0;
fazer {
soma + = soma + 1;
} while (soma <10);
console.log (soma);
// => 15
Enquanto () {} e o {} while () também não exigem um contador, mas use certas condições para determinar se deve executar ou continuar a executar o código lógico.
3. While () {} e faça {} while ()
enquanto () {} e do {} while () são usados principalmente na lógica de negócios, e uma série de operações é executada continuamente para atingir um certo objetivo, como filas de tarefas.
Mas esses dois loops são perigosos porque são controlados apenas por condições de execução por padrão. Se não houver impacto no julgamento da execução no código lógico, ocorrerá um loop morto.
A cópia do código é a seguinte:
var sum = 02
// aviso!
while (soma <10) {
soma = 1 + 12
}
Esse código não é diferente do while (true) {}; portanto, antes do uso, é necessário esclarecer as condições de execução e como afetar as condições de execução.
4. Faça bom uso de declarações de controle de loop
Acredito que todos os engenheiros de JavaScript usaram declarações de quebra, mas as declarações continuadas são relativamente raramente usadas. De fato, existem muitos excelentes projetos de código aberto JavaScript que podem ser encontrados.
Para resolver a função da declaração Continuar, vamos dar uma olhada no código de exemplo primeiro
A cópia do código é a seguinte:
// Node.js Broadcast Server
var net = requer ('net');
var util = requer ('util');
var broadcastServer = net.createServer ();
// loja de clientes
transmissionServer.clients = [];
// Método de transmissão de clientes
net.socket.prototype.broadcast = function (msg) {
VAR clientes = transmissionServer.clients;
// Obtenha o subscrito do cliente de transmissão no centralizado
var index = clients.indexof (this);
for (var i = clients.length -1; i> = 0; --i) {
if (i === index) {
// Se for um cliente de transmissão, o corpo do loop atual será encerrado
continuar;
}
curclient = clientes [i];
if (! curlient.Destroyed) {
curclient.write (
util.format (
'/r [cliente de eco %s: %d] %s/ninput:',
curclient.remoteaddress, curlient.remoteport, msg)
);
}
}
};
// um novo cliente conectado
BroadcastServer.on ('Connection', function (cliente) {
transmissionServer.clients.push (cliente);
// Bem-vindo
client.write ('[servidor de transmissão] bem -vindo!/ninput:');
client.broadcast (cliente, 'juntou -se!');
// identificador de mensagem
client.on ('dados', função (msg) {
client.broadcast (msg);
client.write ('/rinput:');
});
// Desconecte a alça
client.on ('end', function () {
client.broadcast ('esquerda!');
})
});
// Vincular
transmissionServer.Listen (8080, function () {
console.log ('servidor de transmissão vinculado.');
});
Este código implementa um servidor de transmissão com base no módulo Net Node.js. No método de transmissão, usamos a instrução continuação para implementar todos os clientes conectados que estabeleceram conexões, exceto o cliente de transmissão.
O conteúdo do código é bastante simples. Quando um cliente precisa transmitir para outros clientes, o método de transmissão do objeto do cliente correspondente para o cliente é chamado. No método de transmissão, o programa obterá primeiro o subscrito de posição do cliente atual na coleção de soquete do cliente em cache e depois percorre todos os soquetes do cliente. Quando o contador de loop atingir o subscrito de posição obtido antes, o código lógico no corpo do loop atual será ignorado e o próximo loop continuará.
Acredito que os engenheiros que aprenderam a linguagem C/C ++ receberão esse conselho em vários lugares: "Não use as declarações Goto".
Essa declaração "notória" é realmente um controlador de fluxo de código, e os detalhes da declaração Goto não serão explicados em detalhes aqui. No entanto, não existe uma declaração óbvia no JavaScript, mas, por declarações de quebra e continuação, não é difícil encontrar a sombra de Goto em JavaScript.
Isso ocorre porque as declarações de interrupção e continuam as declarações permitem a aceitação de um nome de rótulo definido para redirecionamento de código.
Vamos dar uma olhada no código de exemplo fornecido pelo MDN.
A cópia do código é a seguinte:
var i, j;
Loop1:
for (i = 0; i <3; i ++) {// a primeira para a declaração é rotulada como "loop1"
loop2:
for (j = 0; j <3; j ++) {// a segunda para a declaração é rotulada como "loop2"
if (i == 1 && j == 1) {
continue loop1;
} outro {
console.log ("i =" + i + ", j =" + j);
}
}
}
// a saída é:
// "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 como ele pula "i = 1, j = 1" e "i = 1, j = 2"
Neste código de exemplo, os loops de duas camadas são implementados e um rótulo é definido fora de cada loop, que é usado para chamar a declaração de continuação subsequente.
A primeira camada de loop está no rótulo do loop1, ou seja, no programa subsequente, se o rótulo Loop1 for selecionado na instrução continuação ou na declaração de interrupção, o loop mais externo quebrará.
O loop da segunda camada está no rótulo do loop2 no loop de nível superior. Se a etiqueta Loop2 for selecionada na instrução continuação ou interrupção, ele retornará ao corpo do loop do loop de nível superior.
Usando declarações de controle de loop, podemos interferir no julgamento original da execução do loop, para que um sistema lógico muito complexo possa ser construído. Para ser franco, há muitas declarações de goto no kernel Linux. Quanto ao motivo pelo qual você ainda ouve comentários como as declarações Goto, basta pesquisar no Google.
5. Loop avançado
5.1 Expanda o loop
Vamos primeiro olhar para as duas peças de código e adivinhe qual tem melhor desempenho.
A cópia do código é a seguinte:
// Configurar
var Array = [
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"], "
["Dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados", "dados"]
];
processo de função (item) {
// Faça algo com o item
}
// Caso 1
for (var i = array.length-1; i> = 0; i--) {
for (var j = matriz [i] .Length-1; j> = 0; i--) {
processo (matriz [i] [j]);
}
}
// Caso 2
for (var i = array.length - 1; i> = 0; i = i - 4) {
for (var j = matriz [i] .Length - 1; j> = 0; j = j - 6) {
processo (matriz [i] [j]);
processo (matriz [i] [j - 1]);
processo (matriz [i] [j - 2]);
processo (matriz [i] [j - 3]);
processo (matriz [i] [j - 4]);
processo (matriz [i] [j - 5]);
}
for (var j = matriz [i - 1] .Length - 1; j> = 0; j = j - 6) {
processo (matriz [i] [j]);
processo (matriz [i] [j - 1]);
processo (matriz [i] [j - 2]);
processo (matriz [i] [j - 3]);
processo (matriz [i] [j - 4]);
processo (matriz [i] [j - 5]);
}
for (var j = matriz [i - 2] .Length - 1; j> = 0; j = j - 6) {
processo (matriz [i] [j]);
processo (matriz [i] [j - 1]);
processo (matriz [i] [j - 2]);
processo (matriz [i] [j - 3]);
processo (matriz [i] [j - 4]);
processo (matriz [i] [j - 5]);
}
for (var j = matriz [i - 3] .Length - 1; j> = 0; j = j - 6) {
processo (matriz [i] [j]);
processo (matriz [i] [j - 1]);
processo (matriz [i] [j - 2]);
processo (matriz [i] [j - 3]);
processo (matriz [i] [j - 4]);
processo (matriz [i] [j - 5]);
}
}
Eu preciso passar por todos os elementos do subarray na matriz. Existem duas soluções, uma é o método que geralmente usamos e o outro é expandir a tarefa de loop. A resposta é que o caso 2 tem um desempenho melhor, porque todos os julgamentos de execução entre todos os 6 elementos são excluídos, o que é naturalmente mais rápido que o habitual.
Aqui vamos dar uma olhada em uma solução mais poderosa. Se um link comercial precisar ser processado iterativamente em um grande conjunto de dados e o volume de dados não mudará desde o início da iteração, você poderá considerar o uso de uma tecnologia chamada Duff Disposition. Essa tecnologia recebeu o nome de seu criador Tom Duff, que foi implementado pela primeira vez no idioma C. Mais tarde, Jeff Greenberg o transportou para JavaScript e o modificou através de Andrew b. rei e propôs uma versão mais eficiente.
A cópia do código é a seguinte:
// Crédito: Acelere o seu site (New Riders, 2003)
var iterations = math.floor (valores.length / 8);
Var sobever = valores.length % 8;
var i = 0;
if (sobras> 0) {
fazer {
processo (valores [i ++]);
} while (--leftover> 0);
}
fazer {
processo (valores [i ++]);
processo (valores [i ++]);
processo (valores [i ++]);
processo (valores [i ++]);
processo (valores [i ++]);
processo (valores [i ++]);
processo (valores [i ++]);
processo (valores [i ++]);
} while (--iterations> 0);
O princípio de funcionamento desta técnica é calcular o comprimento dos valores dividido por 8 para obter o número de iterações que precisam ser iteradas e usar a função Math.Mloor () para garantir que o resultado seja um número inteiro e calcule o número que não pode ser divisível por 8 e processar esses elementos e depois 8 são uma única expansão para a TI.
Empacionei este dispositivo e recebi uma API com um sabor assíncrono.
A cópia do código é a seguinte:
função duff (matriz, mapeador) {
var n = Math.Floor (Array.Length / 8);
var L = Array.Length % 8;
var i = 0;
if (l> 0) {
fazer {
mapeador (matriz [i ++]);
} while (--i> 0);
}
fazer {
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
mapeador (matriz [i ++]);
} while (--n> 0);
}
duff ([...], função (item) {
// ...
});
Aqui está um conjunto de testes de desempenho e resultados para as três soluções iterativas acima. http://jsperf.com/spreted-loop
5.2 Loop não nativo
Em qualquer linguagem de programação, os loops podem ser implementados não apenas indiretamente de outras maneiras, mas também de outras maneiras.
Vamos primeiro revisar algum conteúdo da matemática do ensino médio - a fórmula geral das seqüências.
A cópia do código é a seguinte:
Básico
a [1] = 1
a [n] = 2 * a [n - 1] + 1
então
a [n] + 1 = 2 * a [n - 1] + 2
= 2 * (a [n - 1] + 1)
(a [n] + 1) / (a [n - 1] + 1) = 2
Então
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
Depois de ler o cálculo simples acima, você provavelmente adivinha o que discutiremos. Sim, também podemos implementar loops usando a recursão.
A recursão é um método de aplicação muito importante em matemática e ciência da computação, que se refere a uma função que se chama quando é usada.
Na comunidade Node.js, a recursão é usada para implementar uma tecnologia muito importante: a tecnologia de middleware. Esta é uma nova versão do código de implementação do middleware no WebJs que ainda não foi publicado.
A cópia do código é a seguinte:
/**
* Middlewares Run Method
* @param {string} URL URL atual URL
* @param {objeto} req o objeto de solicitação
* @param {objeto} res O objeto de resposta
* @param {function} Out completo retorno de chamada
* @return {function} o servidor
*/
server.runmiddlewares = function (url, req, res, out) {
var index = -1;
var middlewares = this._usingMiddlewares;
// Execute o próximo middleware se houver
função a seguir (err) {
índice ++;
// middleware atual
var Curr = Middlewares [índice];
if (curr) {
var check = novo regexp (curr.route);
// Verifique a rota
if (check.test (url)) {
tentar {
função mais tarde () {
Debug ('Um middleware diz que precisa estar mais tarde em %S', URL);
// as dependências não agora
if (Middlewares.IndexOf (curr)! == Middlewares.Length - 1) {
_later (curr);
índice--;
próximo();
} outro {
Debug ('A dependências de middleware errado');
// este middleware não pode ser executado
fora();
}
}
// Execute o middleware
if (utils.isfunc (curr.handler)) {
// Função de middleware normal
curr.Handler (req, res, próximo, mais tarde);
} else if (utils.isObject (curr.handler) && utils.isfunc (curr.handler.emit)) {
// Objeto do servidor
curr.Handler.emit ('solicitação', req, res, próximo, mais tarde);
} outro {
// Há algo errado no middleware
próximo();
}
} catch (err) {
próximo();
}
} outro {
próximo();
}
} outro {
// para a próxima etapa do pipeline
fora();
}
}
// Se o middleware depende de outros meios de idade,
// pode deixar isso mais tarde correr
função _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;
}
// primeiro middleware
próximo();
devolver isso;
};
Embora esse código pareça duro e complicado, será muito mais claro se o simplificarmos.
A cópia do código é a seguinte:
server.runmiddlewares = function (url, req, res, out) {
var index = -1;
var middlewares = this._usingMiddlewares;
// Execute o próximo middleware se houver
função a seguir (err) {
índice ++;
// middleware atual
var Curr = Middlewares [índice];
if (curr) {
var check = novo regexp (curr.route);
// Verifique a rota
if (check.test (url)) {
// Execute o middleware atual
curr.Handler (req, res, próximo);
} outro {
próximo();
}
} outro {
// para a próxima etapa do pipeline
fora();
}
}
// primeiro middleware
próximo();
devolver isso;
};
A razão pela qual a recursão pode ser usada na implementação do sistema de middleware é que a recursão é o método mais adequado de resposta ao fluxo do programa no Node.js.
Neste código de implementação de middleware, this._usingMiddlewares é uma matriz de loop, a função a seguir () é um corpo de loop, onde o check.test (URL) é a condição de julgamento da execução, e o código de processamento de loop é o primeiro contador de índices no corpo do loop a incrementar por 1 e a próxima função.