Pattern / algoritmo di progettazione JS per evitare ridisegni duplicati in un sistema abbastanza accoppiato

4

Data:

  • una sorta di app web basata su widget
  • molte funzionalità JS
  • alto accoppiamento (comunicazione / callback tra i widget)
  • I widget
  • si disegnano da soli
  • alcuni widget devono eseguire un ridisegno completo e abbastanza costoso ogni volta che viene modificata una delle loro dipendenze.

Problema: ci possono essere catene di dipendenze complicate e diventa difficile assicurarsi che i cambiamenti si verifichino solo una volta per azione dell'utente.

Ad esempio:

  • A deve essere ridisegnato se B o C cambia
  • B dipende dallo stato di C
  • Quindi se C cambia, anche B e entrambi potrebbero finire col causare il routing di A .

Se succede solo poche volte, è facile da risolvere. Ma quando succede dappertutto, diventa un incubo da ingegnere e rende la manutenzione ancora peggiore.

Suppongo che questo sia un problema un po 'comune, quindi deve esserci un metodo per trattare. Questo o i miei progetti sono imperfetti in qualche modo.

Qualche suggerimento? Sarebbe molto apprezzato uno schema di progettazione o un algoritmo per gestire i ridisegni limitanti.

Modifica

Bene, sulla base dei suggerimenti di Randall, ecco cosa sto pensando:

  • Il semaforo è una variabile globale, ma senza elementi multi-threading, quindi in pratica solo un conteggio globale. Diamo un nome a questo S . Ne avrei uno per widget che richiede costosi ridisegni.
  • S ha un segnale e una funzione di attesa. Il segnale incrementa S e aspetta lo decrementa.
  • S è inizializzato con una funzione di callback per l'estrazione del widget.
  • Ogni volta che viene attivato qualcosa (evento utente, ritorno ajax, ecc.) viene chiamato S.signal() .
  • Una volta che l'evento ha finito di cambiare le cose all'interno di un oggetto (dopo aver fatto callback), viene chiamato S.wait() .
  • S.wait() , dopo aver decrementato S controlla se il conteggio è 0. Se lo è, ridisegna.

Quindi se C cambia:

  • C esegue S.signal() ( S==1 )
  • C apporta le sue modifiche, callback a B
  • B esegue S.signal() ( S==2 )
  • B apporta le sue modifiche
  • B esegue S.wait() ( S==1 , nessun ridisegno)
  • B finisce, C ricomincia.
  • C esegue S.wait() ( S==0 , ridisegna)

Come la bandiera sporca ma più di un conteggio sporco e penso che sia più facile da implementare. Può essere esteso per funzionalità aggiuntive abbastanza facile. Se, per qualche motivo, voglio ottimizzarlo in modo che non tutto venga ridisegnato in alcuni casi, posso aggiungere alcuni flag che rappresentano le cose da ridisegnare e ripristinarle ogni volta.

Inoltre, potrebbe essere sostituito con uno stack e fare praticamente la stessa cosa ma con alcune migliori capacità di estensione.

Modifica 2

La soluzione di Izkata si è rivelata di poco conto da implementare e solo leggermente meno flessibile. Sono necessarie solo 2 modifiche:

  • Aggiungi una proprietà timerID al widget che deve essere ridisegnato.
  • Avvolge la funzione di ridisegno in un timer:

Codice JS:

A.draw = function(){
    var that = this; 
    clearTimeout(this.drawTimer);
    this.drawTimer = setTimeout(function(){that._draw();},0);
}
A._draw = function(){
    //old draw code goes here
    //could be made "private" or nested in A.draw
}
  • Non sono necessarie altre modifiche, quindi la tua interfaccia rimane la stessa e funziona a meno che non ti serva per lavorare con il codice Async come le chiamate ajax.
posta slicedtoad 14.08.2014 - 21:52
fonte

1 risposta

3

Buona domanda. Penso che sia necessario separare la cattura dalla necessità di un ridisegno dall'atto del ridisegno. Fondamentalmente, quando le cose dipendenti cambiano, notificano i loro genitori. Il genitore quindi si definisce "sporco", il che significa che ha bisogno di un ridisegno. In un secondo momento, si verifica il ridisegno e il genitore cancella il flag "sporco". Questo è comune nei sistemi di finestre e sistemi di interfaccia utente event-driven (mi dispiace, non riesco a ricordare un nome in grado di utilizzare Google per questo al momento).

Nel tuo caso, se il flag dirty va da clear a set, potresti voler programmare un'operazione di redraw per un breve periodo in futuro. Quindi, possono verificarsi altri eventi che attiveranno il flag dirty da impostare più volte. Dopo che il tempo è passato, è possibile ridisegnare ciò che serve. Speriamo che il tempo di attesa possa essere abbastanza breve da non essere visibile all'utente, ma abbastanza lungo da raccogliere tutti i probabili cambiamenti che devono essere ridisegnati.

Un'alternativa all'approccio basato sul tempo proposto sopra è quello di usare la logica per scoprire in qualche modo che il sistema si è stabilizzato e rinviare i ritocchi fino a quel momento. Non sono sicuro di ciò che attiva i cambiamenti che richiedono il ridisegno, ma forse c'è un punto ovvio in cui sono state apportate tutte le modifiche.

Un terzo approccio potrebbe essere quello di fare in modo che il tuo sistema utilizzi una coda di eventi per guidare il suo lavoro. La coda potrebbe avere la priorità, in modo che gli eventi di modifica dei dati vengano prima degli eventi di ridisegno e che sia necessario un solo evento di ridisegno per widget (o un singolo evento per l'intera pagina).

Dato che SO a volte collassa i commenti, le persone dovrebbero leggere il suggerimento di Izkata di seguito per utilizzare un timeout di zero-delay e la natura single-threaded di JavaScript per creare quella che è effettivamente una coda ad hoc per garantire che i ridisegni vengano eseguiti dopo l'elaborazione principale. Clever.

    
risposta data 14.08.2014 - 22:05
fonte

Leggi altre domande sui tag