Incremento delle prestazioni collegando solo il gestore onblur all'interno del gestore onfocus?

2

Dato una pagina web con campi di input, ha una differenza di prestazioni indipendentemente dal fatto che tu assegni o meno il gestore onblur all'interno del gestore onfocus in questo modo:

var inputFields = document.querySelectorAll("input");

for (i = 0; i < inputFields.length; ++i) {
    var thisInput = inputFields[i];

    thisInput.onfocus = function(){

        console.log("input received focus");

        this.onblur = function(){

            console.log("input lost focus");
            thisInput.onblur = null;

        }//end onblur handler

    }//end onfocus handler  

}//end for loop

Il mio pensiero era che questo avrebbe aggiunto solo l'evento sfocatura quando l'evento di input ha ricevuto lo stato attivo e che il gestore della sfocatura poteva essere rimosso quando veniva eseguita l'elaborazione della sfocatura. Ho pensato che forse questo avrebbe migliorato l'efficienza dal momento che ci sono meno gestori di eventi collegati in un dato momento rispetto all'assegnazione di tutti i campi di input del gestore onblur al momento dell'impostazione. Ci sono dei caveat per impostare il codice in questo modo? Se è importante, verrà utilizzato in un'estensione firefox.

    
posta Eric G 14.01.2015 - 01:01
fonte

3 risposte

1

La differenza di prestazioni sarà trascurabile. Tecnicamente il gestore di focus sta facendo un lavoro extra allegando un gestore di eventi all'elemento, quindi le prestazioni dovrebbero rallentare, tuttavia dubito che questa sia una differenza misurabile.

Se il numero di gestori di eventi rallenta la pagina verso il basso, La delega eventi JavaScript è una risposta migliore ai problemi di prestazioni.

Gli eventi di messa a fuoco e sfocatura sono poco complessi per la delega degli eventi. I browser più recenti supportano gli eventi "focusin" e "focusout", che sono versioni bubbling di "focus" e "blur" rispettivamente:

document.documentElement.addEventListener("focusin", handleFocus, false);
document.documentElement.addEventListener("focusout", handleFocus, false);

I browser meno recenti supportano solo "focus" e "blur" che non hanno bolle. Puoi ancora supportare quei vecchi browser se supportano correttamente addEventListener associando i gestori alla fase di acquisizione di un evento:

document.documentElement.addEventListener("focus", handleFocus, true);
document.documentElement.addEventListener("blur", handleBlur, true);

Questo significa che allega 1 gestore di eventi per evento al caricamento della pagina. La proprietà document.documentElement fa riferimento all'elemento <html> ed è disponibile nel momento in cui JavaScript inizia l'esecuzione, quindi non dovrai più attendere che il DOM sia "pronto".

Quindi devi solo rilevare se il target dell'evento è un elemento che ti interessa prima di iniziare a lavorare:

function handleFocus(event) {
    if (event.target.nodeName !== "INPUT") {
        return;
    }

    console.log("input received focus");
}

function handleBlur(event) {
    if (event.target.nodeName !== "INPUT") {
        return;
    }

    console.log("input lost focus");
}

Quindi, probabilmente stai tentando di risolvere il problema di prestazioni sbagliato.

Il vantaggio che ottieni associando il gestore di eventi "sfocatura" su focus è che si lavora meno con il caricamento della pagina per collegare i gestori di eventi. Puoi mitigare questo problema utilizzando invece la delega degli eventi.

E c'è ancora un vantaggio per la delega degli eventi che non è ovvio. Quando si aggiungono dinamicamente elementi alla pagina, chiamando appendChild(element) o analizzando HTML tramite element.innerHTML = "..." , non è necessario eseguire alcun lavoro aggiuntivo per collegare i gestori di eventi agli elementi <input> aggiunti di recente. Aiuta davvero a ripulire e semplificare il codice del gestore di eventi.

    
risposta data 28.09.2018 - 14:55
fonte
0

does it have a performance difference.

I thought perhaps this would improve efficiency since there are less event handlers attached at a given time versus assigning all input fields the onblur handler at setup

No, non lo farà. Avere molti eventi collegati che non vengono mai chiamati non renderà più lenta la gestione degli altri eventi.

Avere eventi collegati può aumentare l'utilizzo della memoria, ma a meno che non si stia collegando a migliaia di elementi, l'aumento dell'utilizzo della memoria è generalmente trascurabile. Se hai bisogno di allegare a migliaia di elementi per qualche motivo, considera la possibilità di utilizzare la delega degli eventi.

    
risposta data 27.12.2018 - 17:00
fonte
-2

La messa a fuoco attiva sempre la sfocatura e la sfocatura attiva sempre la messa a fuoco, quindi non puoi separarli in alcun modo. Inoltre, gli eventi nativi del mouse e della tastiera sono asincroni, quindi non possono essere bloccati come un evento personalizzato creato a livello di programmazione tramite dispatchEvent :

Unlike "native" events, which are fired by the DOM and invoke event handlers asynchronously via the event loop, dispatchEvent invokes event handlers synchronously. All applicable event handlers will execute and return before the code continues on after the call to dispatchEvent.

Ecco la logica:

focusing on a focusable element fires a focus event at the element

focusing on a focusable element fires a blur event at the previous focused element

Il documento ha ricevuto l'attivo per impostazione predefinita, quindi è sempre il caso. Utilizzare i test W3C come riferimento:

<script>
  var i1 = document.getElementById('i1'),
  i2 = document.getElementById('i2'),
  t1 = async_test("focusing on a focusable element fires a focus event at the element"),
  t2 = async_test("focusing on a focusable element fires a blur event at the previous focussed element");
  i2.onfocus = t1.step_func_done(function(e){
    assert_true(e.isTrusted, "focus event is trusted");
    assert_false(e.bubbles, "focus event doesn't bubble");
    assert_false(e.cancelable, "focus event is not cancelable");
    assert_equals(document.activeElement, i2);
  });
  i1.onblur = t2.step_func_done(function(e){
    assert_true(e.isTrusted, "blur event is trusted");
    assert_false(e.bubbles, "blur event doesn't bubble");
    assert_false(e.cancelable, "blur event is not cancelable");
  });
  i1.focus();
  i2.focus();
</script>

L' API Timing utente può essere utilizzata per testare le prestazioni.

Riferimenti

risposta data 28.09.2018 - 14:39
fonte

Leggi altre domande sui tag