Um ouvinte de evento deve ser chamado se anexado depois que o evento já foi acionado?


8

Um ouvinte de evento deve ser chamado se estiver anexado depois que o evento já foi acionado? E se o evento for disparado apenas uma vez?

O primeiro exemplo que vem à mente é o readyevento no jQuery. O seguinte snippet, quando avaliado após o carregamento da página, ainda chamará o retorno de chamada:

$(document).ready(function () {
    console.log("Works.");
});

A alternativa para esse comportamento pode ser um sinalizador definido quando a página é carregada, forçando o consumidor da API a verificar se o evento já aconteceu e agir de acordo:

if (document.readyState == "complete") {
    console.log("Works.");
} else {
    $(document).ready(function () {
        console.log("Works.");
    });
}

Enquanto o exemplo acima está no contexto de um carregamento de página da Web em que tudo e qualquer coisa (geralmente) precisa acontecer após o carregamento completo da página, os mesmos argumentos podem ser feitos para qualquer componente em um aplicativo que possua eventos "singleton" ( load, start, end, etc.). Um exemplo de um único componente pode ser um mapa com um loadevento acionado para especificar que o mapa foi carregado :

map.on("load", function () {
    console.log("The map has loaded.");
});

O exemplo acima vem da API do ArcGIS para JavaScript, onde esse evento é acionado apenas uma vez e, se um consumidor "espera" o carregamento do mapa após o carregamento do mapa, o ouvinte nunca será chamado. O resultado desejado requer a verificação do estado do mapa antes de o ouvinte ser anexado:

if (map.loaded) {
    console.log("The map has loaded.");
} else {
    map.on("load", function () {
        console.log("The map has loaded.");
    });
}

Qual comportamento está correto, exigindo que o consumidor verifique se um evento já foi acionado ou sempre chamando o retorno de chamada?


5
Você pode estar interessado em extensões de reativo Subjectvs. ReplaySubject, onde os eventos dos últimos replays anteriores para assinantes final enquanto o primeiro não. Ou seja, os criadores do Rx modelaram os dois comportamentos, em vez de decidirem um comportamento definido. - E enquanto os links acima vão para a documentação da versão .NET do Rx ', há também um Rx para JavaScript .
stakx

Respostas:


19

Isso depende se é realmente uma notificação de evento ou estado (que é o que está pronto). Se for um evento, você não informa o ouvinte sobre todos os eventos anteriores. Se for uma Notificação de Estado, você será avisado imediatamente após a assinatura e você estiver no estado especificado.

A parte complicada será onde pode ser um estado ou um evento, dependendo de como você olha para ela - na pior das hipóteses, isso é explicado pela documentação. Na melhor das hipóteses, você escolhe um bom nome que deixa claro o que você quer dizer.


2
+1, também por mencionar as notificações de estado. As notificações de estado são IMO próximas aos futuros e seu tratamento de retornos de chamada, por exemplo, em Scala ( docs.scala-lang.org/overviews/core/futures.html ).
Giorgio

Interessante, eu não tinha pensado assim. Você classificaria load, startou endo mesmo que ready, como uma notificação de estado?
Whymarrh

@ Whymarrh: Isso vai depender do contexto, mas isso soa como eventos para mim. Eu tenderia a nomear a notificação do estado como perguntas ... pronta? começado? corrida? mas é claro que você pode precisar ajustá-lo a uma convenção de nomenclatura existente.
jmoreno

3
Parece-me que eventos podem ser interpretados como algo que ocorre uma vez para mudar o estado. Isso significa que eles são muito duradouros, praticamente um único momento. Um estado, por outro lado, tem vida mais longa e consiste em vários momentos. loadnão é um evento nem um estado. loadingStartedé um evento e loadingé um estado.
Jeroen Vannevel 04/12/14

5

Em geral, não .

Os ouvintes de eventos não devem ser chamados se estiverem anexados após o evento já ter sido acionado. "Você dorme, você perde."

Existem algumas exceções importantes. $(document).ready()é talvez o exemplo perfeito - um evento antes do qual todo o contexto da avaliação não é estabelecido de maneira confiável ou completa e serve como um marcador "o processamento completo da função começa aqui".

Se, no entanto, você definir a regra de que um manipulador de eventos deve ser acionado, mesmo que seja instalado e / ou ativado após a ocorrência do evento, você declarou que todos os eventos devem ou devem ser armazenados em buffer desde o início até o final da execução do programa, para todo evento concebível. Senão, pode haver manipuladores de eventos estabelecidos em algum evento, em algum lugar no futuro, que você não tenha informações suficientes para saber se deve acionar quando ele estiver estabelecido. Isso significa que você teria que instrumentar todas as fontes de eventos possíveis e armazenar em buffer infinitamente todas elas também. Isso leva o processamento de eventos a partir de uma avaliação lenta (e de todos os seus benefícios de desempenho) até uma avaliação mais ágile para o que estiver no outro extremo do espectro. Avaliação frenética baseada em suposições catastrofizadas sobre quais eventos talvez precisem ser tratados posteriormente?

Os eventos tendem a ser transitórios e numerosos. Definir regras que exigem que cada uma seja armazenada em buffer, sem limitação, na possibilidade de serem eventualmente exploradas - é suicídio por desempenho. Além disso, não há um grande requisito para isso, pois os manipuladores geralmente podem ser estabelecidos no início da vida do programa.

As exceções à regra são casos extremos - cargas de documentos ou subsistemas, por exemplo, que são eventos essenciais, exclusivos e importantes que não são capturáveis ​​ou manipuláveis. Isso é muito próximo aos seus eventos "singleton". Outro grupo que pode precisar de tratamento especial são erros significativos, eventos de segurança ou alterações de status que têm uma necessidade excepcional de serem sinalizados, mesmo que não haja assinantes no sinalizador no momento em que o evento ocorreu.

Uma observação final: um evento "pronto" é sutilmente diferente de um evento "carregado". Embora eles geralmente não sejam claramente distinguidos (por exemplo, HTML onloade jQuery são $(document).ready()considerados logicamente muito semelhantes), e ambos sinalizam a disponibilidade de um recurso ou ambiente de processamento - mas não são exatamente iguais. Carregar (ou terminar) é um evento real - algo sinalizado da infraestrutura para o consumidor. Prontidão, no entanto, é mais o ponto de encontroda infraestrutura carregando o recurso / ambiente e o consumidor se preparando para consumir / tirar proveito dessa disponibilidade. A prontidão vem após o carregamento e é um daqueles eventos / pontos de coordenação especiais designados que devem ser tratados como enfileirados porque você não pode capturá-lo de outra maneira. O fato de haver alguns casos muito especiais, no entanto, não significa que todo evento deva ser acionável a posteriori .


Erm, você quis dizer "onload" do html?
StarWeaver

@ StarWeaver Obrigado. Não tenho certeza se eu escorreguei ou minha autocorreção ambiciosa, mas você está totalmente certo. Fixo.
Jonathan Eunice

NP, eu não sou tudo com html post 4, mas parecia estranho. Boa explicação também.
StarWeaver
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.