2015-07-04 12 views
8

Desidero implementare un evento personalizzato che può essere "trasmesso" anziché inviato a specifici obiettivi. Solo quegli elementi che si sono registrati come ascoltatori per tali eventi li riceveranno.Come vengono implementati eventi di trasmissione personalizzati in JavaScript (o jQuery)?

Quello che ho in mente sembrerebbe il seguente.

In primo luogo, in vari luoghi del codice, non ci sarebbe enunciati della forma

some_subscriber.on_signal('some_signal', some_handler); 

sto usando il termine signal come abbreviazione di "evento di trasmissione". Nell'espressione sopra, some_subscriber si registra come listener di un tipo (chiamato 'some_signal') di tali segnali, fornendo un gestore per questo.

Altrove nel codice, ci sarebbero enunciati della forma

publisher.signal_types[ 'some_signal' ].broadcast(event_data); 

Quando affermazioni come queste vengono eseguiti, viene generato un nuovo evento e "trasmissione". Con questo intendo che il codice che chiama il metodo broadcast non ha informazioni dirette sugli ascoltatori per il segnale che sta emettendo.


ho implementato uno schizzo di questa idea in this jsFiddle, principalmente al fine di illustrare ciò che descritto in parole sopra . (Non è certamente di produzione, e non sono particolarmente sicuro che possa essere fatto così.)

Gli elementi chiave di questa implementazione sono i seguenti. In primo luogo, gli oggetti editore non tenere traccia dei loro abbonati, come si può vedere nella realizzazione di un metodo factory per un tale editore, indicati di seguito:

function make_publisher (signal_types) { 

    // ... 

    var _ 
    , signal = {} 
    , ping = function (type) { 
        signal[ type ].broadcast(...); 
       } 
    ; 

    signal_types.forEach(function (type) { 
          signal[ type ] = $.register_signal_type(type); 
         }); 

    return { signal_types: signal_types, ping: ping }; 
} 

Questo oggetto editore espone solo due voci: i tipi di segnali trasmessi (in signal_types) e un metodo ping. Quando il suo metodo ping viene richiamato, l'editore risponde trasmettendo un segnale:

signal[ type ].broadcast(...) 

I destinatari finali di questa trasmissione sono in nessun posto essere visto in questo codice.

In secondo luogo, in altre parti del codice, gli abbonati si registrano in qualità di uditori di questi segnali di trasmissione, in questo modo

$(some_selector).on_signal(signal_type, some_handler); 

Nota: E 'praticamente impossibile per illustrare la logica di questo regime con un esempio che è sia piccolo che realistico. La ragione di ciò è che la forza di questo schema è che supporta un accoppiamento molto lento tra il codice del publisher e il codice dell'abbonato, e questa è una caratteristica che non è mai necessaria in un piccolo esempio. Al contrario, in un piccolo esempio, il codice che implementa un tale accoppiamento libero si presenta invariabilmente come inutilmente complesso. È quindi importante tenere presente che questa apparente complessità eccessiva è un artefatto del contesto. L'accoppiamento lento è molto utile in progetti di grandi dimensioni. In particolare, l'accoppiamento lento tramite un modello di tipo publisher/sottoscrittore è una delle caratteristiche essenziali di MVC.


La mia domanda è: c'è un migliore (o almeno più standard) modo per ottenere questo effetto di eventi personalizzati "broadcasting"?

(Mi interessa entrambe le risposte jQuery-based così come "puri JS" quelli.)


Un precedente, è stata accolta la versione sfortunata di questo post con incomprensione quasi universale, e (ovviamente) il down-voting troppo tipico. Con una sola eccezione, tutti i commenti mi hanno sfidato proprio nelle premesse del post, e uno ha messo in discussione direttamente la mia comprensione delle basi della programmazione basata sugli eventi, ecc. Spero che presentando un esempio funzionante di ciò che intendo almeno non sarà assolutamente inconcepibile come quando l'ho descritto solo con le parole. Fortunatamente, l'unico commento utile che ho ricevuto su quel post precedente mi ha informato della funzione jQuery.Callbacks. Questo era davvero un suggerimento utile; l'implementazione dello schizzo menzionata nel post è basata su jQuery.Callbacks.

+1

Una libreria di eventi personalizzati generici ........ https://github.com/mmikowski/jquery.event.gevent. – Piyuesh

+1

Sono curioso di sapere se eri a conoscenza dei metodi nativi ** 'dispatchEvent' ** e **' addEventListener' **, specialmente quando entrambi possono essere usati sull'oggetto ** 'document' **, quindi l'unica dipendenza per entrambi *** broadcasting *** e *** listening *** diventano l'oggetto globale ** 'document' ** per *** *** *** *** e *** subscribing *** rispettivamente. Sono anche interessato a sapere che se tu fossi a conoscenza di loro, quali carenze hai notato utilizzando questi metodi nativi che ti hanno incoraggiato a proporre la tua soluzione. Grazie. –

+0

@TahirAhmed: No, non ero a conoscenza di questi metodi. Leggerò di più su di loro. Grazie. (Detto questo, tendo ad evitare i metodi nativi, in favore di jQuery, per motivi di compatibilità con i browser.) – kjo

risposta

9

Bene.

Quindi penso che cosa si può fare è utilizzare i nativi dispatchEvent e addEventListener metodi e utilizzare document come unico elemento sia per la pubblicazione e sottoscrizione a quegli eventi.Qualcosa di simile:

var myCustomEvent = new Event('someEvent'); 
document.dispatchEvent(myCustomEvent); 
... 
document.addEventListener('someEvent', doSomething, false); 

E per rendere cross-browser, si potrebbe:

var myCustomEvent = new Event('someEvent'); 
document.dispatchEvent(myCustomEvent); 
... 
if (document.addEventListener) { 
    document.addEventListener('someEvent', doSomething, false); 
} else { 
    document.attachEvent('someEvent', doSomething); 
} 

Si può leggere di più su questo argomento here e here. Spero che questo ti aiuti.

1

La mia domanda è: esiste un modo migliore (o almeno più standard) per ottenere questo effetto di eventi personalizzati "broadcasting"?

No, non esiste un modo più standard di pubblicare/sottoscrivere in Javascript. Non è incorporato direttamente nella lingua o nel browser e non ci sono standard per la piattaforma di cui sono a conoscenza.

Avete diverse opzioni (molte delle quali sembrano essere a conoscenza) per mettere insieme il vostro sistema.

si poteva scegliere un oggetto specifico, come l'oggetto document o l'oggetto window o un nuovo oggetto si crea e si utilizza jQuery .on() e .trigger() con l'oggetto come una stanza di compensazione centrale per mettere insieme una pubblicazione/modello di sottoscrizione-like. Potresti anche nascondere l'esistenza di quell'oggetto dal tuo uso effettivo semplicemente codificandolo in poche funzioni di utilità, se lo desideri.

Oppure, come sembra che tu sappia, è possibile utilizzare la funzionalità jQuery.Callbacks. C'è persino un codice di esempio di pubblicazione/sottoscrizione nello jQuery doc.

Oppure, è possibile trovare una libreria di terze parti che offre un modello di pubblicazione/sottoscrizione un po 'tradizionale.

Oppure, è possibile creare il proprio da zero che in realtà implica solo la conservazione di un elenco di funzioni di callback associate a un evento specifico, quindi quando tale evento viene attivato, è possibile chiamare ciascuna funzione di callback.

Problemi correlati