No nó, muitos objetos emitem eventos. Por exemplo, um servidor TCP transmitirá um evento "Connect" sempre que um cliente solicitar uma conexão e, por exemplo, sempre que um pouco de dados for lido, o sistema de arquivos transmitirá um evento "dados". Esses objetos são chamados de emissores de eventos no nó. O transmissor de eventos permite que os programadores assinem eventos de interesse e vinculem a função de retorno de chamada aos eventos relacionados, para que a função de retorno de chamada seja chamada sempre que o transmissor de eventos emite um evento. O modo de publicação/assinatura é muito semelhante ao modo GUI tradicional, como o programa receberá notificações correspondentes quando o botão for clicado. Usando esse modelo, os programas do servidor podem reagir quando alguns eventos ocorrem, como conexão com o cliente, dados disponíveis no soquete ou arquivo fechado.
Você também pode criar seu próprio transmissor de eventos. De fato, o Node fornece uma pseudo-classe de Evento Especial que pode ser usada como uma classe base para criar seu próprio transmissor de eventos.
Entenda o modo de retorno de chamada
A programação assíncrona não usa valores de retorno da função para indicar o final de uma chamada de função, mas adota um estilo de passagem subsequente.
"Estilo de passagem de continuação" (CPS: estilo de passagem de continuação) é um estilo de programação, e o controle de processos é explicitamente passado para a próxima operação ...
As funções no estilo CPS aceitarão uma função como um parâmetro extra. Esta função é usada para apontar explicitamente o próximo processo de controle do programa. Quando a função CPS calcula seu "valor de retorno", chamará a função que representa o próximo processo do programa e pega o "valor de retorno" da função CPS como seu parâmetro.
De Wikipedia - http://en.wikipedia.org/wiki/Continuation-Passing_Style
Nesse estilo de programação, cada função chamará uma função de retorno de chamada após a execução, para que o programa possa continuar sendo executado. Você entenderá mais tarde que o JavaScript é muito adequado para esse estilo de programação. Aqui está um exemplo de carregamento de arquivos na memória no nó:
A cópia do código é a seguinte:
var fs = requer ('fs');
fs.readfile ('/etc/passwd', função (err, filecontent) {
if (err) {
lança err;
}
console.log ('Conteúdo do arquivo', FileContent.toString ());
});
Neste exemplo, você passa uma função anônima em linha como o segundo parâmetro do FS.Readfile. De fato, isso está usando a programação do CPS porque você entrega o processo subsequente da execução do programa na função de retorno de chamada.
Como você pode ver, o primeiro parâmetro da função de retorno de chamada é um objeto de erro. Se ocorrer um erro no programa, esse parâmetro será uma instância da classe de erro. Este é um padrão comum para a programação do CPS no nó.
Entenda o modo de transmissor de eventos
No modo de retorno de chamada padrão, uma função é passada como um parâmetro para a função a ser executada. Esse modo funciona muito bem em cenários em que o cliente precisa ser notificado após a conclusão da função. No entanto, se ocorrerem vários eventos durante a execução de uma função ou eventos várias vezes, esse padrão não será adequado. Por exemplo, se você deseja ser notificado toda vez que o soquete receber dados disponíveis, descobrirá que o modo de retorno de chamada padrão não é muito útil nesse cenário. No momento, o modo de transmissor de eventos é útil. Você pode usar um conjunto de interfaces padrão para separar claramente o gerador e o ouvinte de eventos.
Ao usar o modo gerador de eventos, dois ou mais objetos estão envolvidos - transmissores de eventos e um ou mais ouvintes de eventos.
Um transmissor de eventos, como o nome sugere, é um objeto que pode gerar eventos. O ouvinte do evento está com o código vinculado ao transmissor de eventos para ouvir tipos específicos de eventos, como o exemplo a seguir:
A cópia do código é a seguinte:
var req = http.request (opções, função (resposta) {
Response.on ("Data", function (dados) {
console.log ("Alguns dados da resposta", dados);
});
Response.on ("end", function () {
console.log ("Resposta terminada");
});
});
req.end ();
Este código demonstra duas etapas necessárias ao criar uma solicitação HTTP para acessar um servidor HTTP remoto usando a API HTTP.Request do Node (consulte o capítulo posterior). A primeira linha adota o "estilo de passagem de continuação" (CPS: estilo de passagem de continuação), passando uma função embutida que será chamada quando o HTTP responder. A API de solicitação HTTP usa o CPS aqui porque o programa precisa continuar executando operações subsequentes após a execução da função HTTP.Request.
Quando o http.request for executado, a função de retorno de chamada anônima será chamada e o objeto de resposta HTTP será transmitido a ele como um parâmetro. Este objeto de resposta HTTP é um transmissor de eventos. De acordo com o documento do Node, ele pode emitir muitos eventos, incluindo dados e fim. As funções de retorno de chamada que você se registrarão serão chamadas sempre que o evento ocorrer.
Como lição, use o modo CPS quando precisar recuperar os direitos de execução após a conclusão da operação solicitada e use o modo de transmissor de eventos quando os eventos podem ocorrer várias vezes.
Entenda os tipos de eventos
Os eventos transmitidos têm um tipo representado por uma string. O exemplo anterior contém dois tipos de eventos: "dados" e "end", que são qualquer seqüência definida pelo transmissor de eventos. No entanto, é convencionalmente constitutivo que os tipos de eventos geralmente sejam compostos por palavras minúsculas que não contêm caracteres vazios.
Você não pode usar o código para inferir quais tipos de eventos o transmissor de eventos pode gerar, porque a API do transmissor de eventos não possui um mecanismo de introspecção; portanto, a API que você está usando deve ter documentação para indicar que ela pode emitir esses tipos de eventos.
Depois que um evento ocorre, o transmissor de eventos chamará o ouvinte relacionado ao evento e passará os dados relevantes para o ouvinte como um parâmetro. No exemplo anterior, http.request, a função de retorno de chamada do evento "Data" aceita um objeto de dados como seu primeiro e único parâmetro, enquanto o "end" não aceita nenhum dado. Esses parâmetros como parte do contrato da API também são subjetivamente definidos pelo autor da API. As assinaturas de parâmetros dessas funções de retorno de chamada também serão explicadas na documentação da API de cada emissor de evento.
Embora o transmissor de eventos seja uma interface que serve todos os tipos de eventos, o evento "erro" é uma implementação especial no nó. A maioria dos transmissores de eventos no nó gerará um evento de "erro" quando ocorrer um erro no programa. Se o programa não ouvir o evento "Erro" de um transmissor de eventos, o transmissor de eventos notará e lançará uma exceção não capturada quando o erro ocorrer.
Você pode executar o seguinte código no Node Perl para testar o efeito, que simula um transmissor de eventos que pode gerar dois eventos:
A cópia do código é a seguinte:
var em = novo (requer ('eventos'). EventEmitter) ();
em.emit ('Event1');
em.emit ('erro', novo erro ('meu erro'));
Você verá a seguinte saída:
A cópia do código é a seguinte:
var em = novo (requer ('eventos'). EventEmitter) ();
indefinido
> em.emit ('Event1');
falso
> em.emit ('erro', novo erro ('meu erro'));
Erro: meu erro
em Repl: 1: 18
em replserver.eval (repl.js: 80: 21)
em Repl.js: 190: 20
em replserver.eval (repl.js: 87: 5)
na interface. <nonymous> (Repl.js: 182: 12)
na interface.emit (events.js: 67: 17)
na interface._online (readline.js: 162: 10)
em interface._line (readline.js: 426: 8)
na interface._ttywrite (readline.js: 603: 14)
em Readstream. <nonymous> (readline.js: 82: 12)
>
Na linha 2 do código, um evento chamado "Event1" é emitido, sem nenhum efeito, mas quando o evento "erro" é emitido, o erro é lançado na pilha. Se o programa não estiver em execução no ambiente da linha de comando Perl, o programa travará devido a uma exceção não capturada.
Usando a API do transmissor de eventos
Qualquer objeto que implementa o modo de transmissor de eventos (como soquete TCP, solicitação HTTP, etc.) implementa o seguinte conjunto de métodos:
A cópia do código é a seguinte:
.Addlistener e .On - Adicionar ouvinte de eventos para eventos do tipo especificado
.once - Ligue um ouvinte de evento que executa apenas uma vez para o evento do tipo especificado
.RemoveEventListener - Exclua um ouvinte vinculado ao evento especificado
.removealleventListener - Exclua todos os ouvintes vinculados ao evento especificado
Vamos apresentá -los em detalhes abaixo.
Funções de retorno de chamada de ligação usando .addlistener () ou .on ()
Ao especificar o tipo de evento e a função de retorno de chamada, você pode registrar as ações executadas quando o evento ocorrer. Por exemplo, se houver blocos de dados disponíveis quando um arquivo lê um fluxo de dados, ele emitirá um evento "dados". O código a seguir mostra como passar uma função de retorno de chamada para deixar o programa informar que o evento de dados ocorreu.
A cópia do código é a seguinte:
Função recebida (dados) {
console.log ("Obteve dados do arquivo de leitura de arquivo: %j", dados);
}
readstream.addlistener ("dados", recebido);
Você também pode usar .on, que é apenas a abreviação de .Addlistener. O código a seguir é o mesmo que o acima:
A cópia do código é a seguinte:
Função recebida (dados) {
console.log ("Obteve dados do arquivo de leitura de arquivo: %j", dados);
}
readstream.on ("dados", recebido);
No código anterior, você pode usar uma função nomeada definida com antecedência como a função de retorno de chamada e também pode usar uma função anônima embutida para simplificar o código:
A cópia do código é a seguinte:
readstream.on ("dados", function (dados) {
console.log ("Obteve dados do arquivo de leitura de arquivo: %j", dados);
});
Como mencionado anteriormente, o número de parâmetros e assinaturas passadas para a função de retorno de chamada depende do objeto de transmissor de eventos específicos e do tipo de evento. Eles não são padronizados. O evento "dados" pode passar em um objeto de buffer de dados, o evento "erro" passa um objeto de erro e o evento "final" do fluxo de dados não passa nenhum dado para o ouvinte do evento.
Vincular vários ouvintes de eventos
O modo de transmissor de eventos permite que vários ouvintes de eventos ouçam o mesmo tipo de evento do mesmo transmissor de eventos, como:
A cópia do código é a seguinte:
Eu tenho alguns dados aqui.
Eu também tenho alguns dados aqui.
O transmissor de eventos é responsável por invocar todos os ouvintes vinculados ao tipo de evento especificado na ordem em que o ouvinte está registrado, ou seja:
1. Quando ocorre um evento, o ouvinte do evento não pode ser chamado imediatamente, e pode haver outros ouvintes do evento.
2. É anormal ser jogado na pilha, o que pode ser por causa de um bug no código. Quando um evento é transmitido, se um ouvinte de eventos lançar uma exceção quando é chamado, alguns ouvintes do evento podem nunca ser chamados. Nesse caso, o transmissor de eventos pega a exceção e também pode lidar com isso.
Veja o seguinte exemplo:
A cópia do código é a seguinte:
readstream.on ("dados", function (dados) {
lançar um novo erro ("algo errado aconteceu");
});
readstream.on ("dados", function (dados) {
console.log ('Eu também tenho alguns dados aqui.');
});
Como o primeiro ouvinte lança uma exceção, o segundo ouvinte não será chamado.
Use .removelistener () para remover um ouvinte de eventos do transmissor de eventos
Se você não se importa mais com um evento em um objeto, pode cancelar o ouvinte de eventos registrado especificando o tipo de evento e a função de retorno de chamada, como este:
A cópia do código é a seguinte:
Função recebida (dados) {
console.log ("Obteve dados do arquivo de leitura de arquivo: %j", dados);
}
readstream.on ("dados", recebido);
// ...
readstream.removelistener ("dados", recebido);
Neste exemplo, a última linha remove um ouvinte de evento que pode ser chamado a qualquer momento no futuro do objeto transmissor de eventos.
Para excluir o ouvinte, você deve nomear a função de retorno de chamada, porque o nome da função de retorno de chamada é necessário ao adicionar e excluí -lo.
Use .Once () para permitir que a função de retorno de chamada seja executada no máximo uma vez
Se você deseja ouvir um evento que é executado no máximo uma vez ou estiver interessado apenas na primeira vez em que um evento ocorre, você pode usar a função .once ():
A cópia do código é a seguinte:
Função recebida (dados) {
console.log ("Obteve dados do arquivo de leitura de arquivo: %j", dados);
}
readstream.once ("dados", recebido);
No código acima, a função recebida será chamada apenas uma vez. Se o objeto Readstream emite um evento de dados, a função de retorno de chamada recebida será acionada e será acionada apenas uma vez.
Na verdade, é apenas um método conveniente, porque pode ser implementado de maneira muito simples, assim:
A cópia do código é a seguinte:
var eventEMitter = requer ("eventos"). EventEmitter;
EventEmitter.prototype.once = function (tipo, retorno de chamada) {
var que = this;
this.on (tipo, função ouvinte () {
that.Removelistener (tipo, ouvinte);
retorno de chamada.Apply (isso, argumentos);
});
};
No código acima, você redefine a função EventEmitter.prototype.once e também redefine a função única de cada objeto herdado do EventEmitter. O código simplesmente usa o método .on (). Depois que um evento for recebido, use .removeEventListener () para cancelar o registro da função de retorno de chamada e chamar a função original de retorno de chamada.
Nota: O código anterior usa o método function.apply (), que aceita um objeto e o leva como a continha essa variável e uma matriz de parâmetros. No exemplo anterior, a matriz de parâmetros não modificada é transparente passada para a função de retorno de chamada através do transmissor de eventos.
Remova todos os ouvintes de eventos do transmissor de eventos com .removeAlllisteners ()
Você pode remover todos os ouvintes registrados no tipo de evento especificado do transmissor de eventos da seguinte forma:
A cópia do código é a seguinte:
emissor.RemoveAlllisteners (tipo);
Por exemplo, você pode cancelar o ouvinte de todos os sinais de interrupção do processo como este:
A cópia do código é a seguinte:
Process.RemoveAlllisteners ("Sigterm");
Nota: Como lição, é recomendável que você use apenas essa função quando souber exatamente o que é excluído. Caso contrário, você deve permitir que outras partes do aplicativo excluam a coleção do ouvinte do evento, ou também pode permitir que essas partes do programa se encarregem de remover o próprio ouvinte. Mas não importa o quê, essa função ainda é útil em alguns cenários raros, como quando você está se preparando para fechar um transmissor de eventos ou fechar todo o processo de maneira ordenada.
Crie um transmissor de evento
Os transmissores de eventos tornam as interfaces de programação mais gerais de uma ótima maneira. Em um modo de programação comum e fácil de entender, o cliente chama diretamente várias funções, enquanto no modo transmissor de eventos, o cliente está vinculado a vários eventos, o que tornará seu programa mais flexível. (Nota do tradutor: esta frase não é muito confiante, publicando o texto original: o emissor de eventos fornece uma ótima maneira de tornar uma interface de programação mais genérica. Quando você usa um padrão de entendimento comum, os clientes se ligam aos eventos em vez de invocar funções, tornar seu programa mais flexível.)
Além disso, usando transmissores de eventos, você também pode obter muitos recursos, como vincular vários ouvintes não relacionados no mesmo evento.
Herdado do transmissor de eventos de nó
Se você estiver interessado no modo de emissor de eventos do Node e pretende usá-lo em seu próprio aplicativo, poderá criar uma pseudo-classe herdando o EventEMitter:
A cópia do código é a seguinte:
uTIL = requer ('util');
var eventEMitter = requer ('eventos'). EventEmitter;
// Este é o construtor da MyClass:
var myclass = function () {
}
util.Irits (myClass, EventEmitter);
Nota: Util.Irits cria a cadeia de protótipo da MyClass, para que sua instância do MyClass possa usar o método do protótipo de EventEMitter.
Evento de lançamento
Ao herdar do EventEmitter, o MyClass pode lançar eventos como este:
A cópia do código é a seguinte:
Myclass.prototype.somemethod = function () {
this.emit ("Evento personalizado", "argumento 1", "argumento 2");
};
No código acima, quando o método Somemethond for chamado pela instância do MyClass, um evento chamado "Evento Cuteom" será emitido. Este evento também emitirá duas seqüências como dados: "Argumento 1" e "Argumento 2", que serão passados como parâmetros para o ouvinte do evento.
O cliente da instância do MyClass pode ouvir o evento "Evento personalizado" como este:
A cópia do código é a seguinte:
var myInstance = new MyClass ();
MyInstance.on ('Evento personalizado', função (STR1, STR2) {
console.log ('obteve um evento personalizado com os str1 %s e str2 %s!', str1, str2);
});
Por exemplo, você pode criar uma classe de ticker que emite eventos "tick" uma vez por segundo:
A cópia do código é a seguinte:
var util = requer ('util'),
EventEmitter = requer ('eventos'). EventEmitter;
var ticker = function () {
var self = this;
setInterval (function () {
self.emit ('tick');
}, 1000);
};
util.Irits (ticker, EventEmitter);
Os clientes que usam a classe Ticker podem mostrar como usar a classe Ticker e ouvir eventos "Tick".
A cópia do código é a seguinte:
var ticker = new Ticker ();
ticker.on ("tick", function () {
console.log ("tick");
});
resumo
O modo de transmissor de eventos é um padrão de reentrada que pode ser usado para dissociar o objeto transmissor de eventos de um conjunto de código para um evento específico.
Você pode usar o Event_emitter.on () para registrar os ouvintes para obter tipos específicos de eventos e não registrar com event_emitter.removelistener ().
Você também pode criar seu próprio emissor de eventos herdando o EventEmitter e simplesmente usando a função .emit ().