Violazione L’attività JavaScript a esecuzione prolungata ha richiesto xx ms

Recentemente, ho ricevuto questo tipo di avvertimento, e questa è la mia prima volta a ottenerlo:

[Violation] Long running JavaScript task took 234ms [Violation] Forced reflow while executing JavaScript took 45ms 

Sto lavorando a un progetto di gruppo e non ho idea da dove provenga. questo non è mai successo prima. All’improvviso appare quando qualcun altro è coinvolto nel progetto. Come trovo quale file / funzione provoca tale avviso? Ho cercato una risposta, ma soprattutto la soluzione su come risolverlo. Non posso risolverlo se non riesco nemmeno a trovare la fonte del problema.

Note: in questo caso l’avviso appare solo su chrome. Ho provato ad usare Edge, non ho ricevuto avvertimenti simili. Non l’ho ancora provato su Mozilla.

Aggiornamento: ho persino ricevuto l’errore da jquery.min.js dicendo:

 [Violation] Handler took 231ms of runtime (50ms allowed) jquery.min.js:2 

Aggiornamento: Chrome 58+ ha nascosto questi e altri messaggi di debug per impostazione predefinita. Per visualizzarli, fai clic sulla freccia accanto a “Informazioni” e seleziona “Verbose”.

Aggiornamento 2: Chrome 57 ha triggersto “Nascondi violazioni” per impostazione predefinita. Per ritriggersrli devi abilitare i filtri e deselezionare la casella “nascondi le violazioni”.

improvvisamente appare quando qualcun altro è coinvolto nel progetto

Penso che sia più probabile che tu abbia effettuato l’aggiornamento a Chrome 56. Questo avviso è una (imo) meravigliosa nuova funzione: ti preghiamo di spegnerlo solo se sei disperato e il tuo valutatore ti terrà lontano da te. I problemi sottostanti ci sono negli altri browser ma i browser non ti dicono che c’è un problema. Il biglietto Chromium è qui ma non ci sono discussioni interessanti su questo: https://bugs.chromium.org/p/chromium/issues/detail?id=662497

Questi messaggi sono avvertimenti anziché errori perché in realtà non causeranno problemi importanti. Potrebbe causare la caduta dei fotogrammi o comunque un’esperienza meno liscia.

Vale la pena indagare e correggere per migliorare la qualità della tua applicazione. Il modo per farlo è prestando attenzione a quali circostanze appaiono i messaggi e facendo test delle prestazioni per restringere il punto in cui si sta verificando il problema. Il modo più semplice per avviare il test delle prestazioni è inserire un codice come questo:

 function someMethodIThinkMightBeSlow() { const startTime = performance.now(); // Do the normal stuff for this function const duration = performance.now() - startTime; console.log(`someMethodIThinkMightBeSlow took ${duration}ms`); } 

Se vuoi diventare più avanzato, puoi anche utilizzare il profiler di Chrome: https://developers.google.com/web/tools/chrome-devtools/rendering-tools/

Oppure fai uso di una libreria di benchmark come questa: https://benchmarkjs.com/

Una volta che hai trovato un codice che richiede molto tempo (50ms è la soglia di Chrome), hai un paio di opzioni:

  1. Tagliare alcune / tutte quelle attività che potrebbero non essere necessarie
  2. Scopri come eseguire lo stesso compito più velocemente
  3. Dividere il codice in più passaggi asincroni

(1) e (2) possono essere difficili o impossibili. Ma a volte davvero facile e dovrebbe essere il tuo primo tentativo. Se necessario, dovrebbe essere sempre ansible fare (3). Per fare questo userete qualcosa come

 setTimeout(functionToRunVerySoonButNotNow); 

o

 // This one is not available natively in IE, but there are polyfills available. Promise.resolve().then(functionToRunVerySoonButNotNow); 

Puoi leggere di più sulla natura asincrona di javascript qui:

http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/

Questi sono solo avvertimenti come tutti hanno menzionato. Tuttavia, se sei interessato a risolverli (cosa che dovresti), devi prima identificare cosa sta causando l’avviso. Non c’è una sola ragione per cui è ansible ottenere un avviso di reflow forzato.
Qualcuno ha creato un elenco per alcune opzioni possibili. È ansible seguire la discussione per ulteriori informazioni.
Ecco il succo delle possibili ragioni:

Ciò che impone layout / reflow

Tutte le proprietà o i metodi sottostanti, quando richiesti / richiamati in JavaScript, attiveranno il browser per calcolare in modo sincrono lo stile e il layout *. Questo è anche chiamato “reflow” o ” layout thrashing” ed è un comune collo di bottiglia delle prestazioni.

Elemento

Metriche sulla scatola

  • elem.offsetLeft , elem.offsetTop , elem.offsetWidth , elem.offsetHeight , elem.offsetParent
  • elem.clientLeft , elem.clientTop , elem.clientWidth , elem.clientHeight
  • elem.getClientRects() , elem.getBoundingClientRect()

Scorri cose

  • elem.scrollBy() , elem.scrollTo()
  • elem.scrollIntoView() , elem.scrollIntoViewIfNeeded()
  • elem.scrollWidth , elem.scrollHeight
  • elem.scrollLeft , elem.scrollTop anche, impostandoli

Messa a fuoco

  • elem.focus() può triggersre un doppio layout forzato ( fonte )

Anche…

  • elem.computedRole , elem.computedName
  • elem.innerText ( fonte )

getComputedStyle

window.getComputedStyle() in genere impone il ricalcolo di stile ( origine )

window.getComputedStyle() layout, se una delle seguenti condizioni è vera:

  1. L’elemento è in un albero ombra
  2. Ci sono delle query multimediali (quelle relative alla visualizzazione). In particolare, uno dei seguenti: ( sorgente ) * min-width min-height , max-width max-height , width , height * aspect-ratio min-aspect-ratio , aspect-ratio min-aspect-ratio max-aspect-ratio
    • device-pixel-ratio , resolution , orientation
  3. La proprietà richiesta è una delle seguenti: ( fonte )
    • height , width * in top , a right , in bottom , a left * margin [ -top , -bottom , -bottom , -bottom , o stenografia ] solo se il margine è fisso. * padding [ -top , -top , -top , -bottom , o shorthand ] solo se il padding è fisso. * transform , transform-origin , perspective-origin * translate , rotate , scale * webkit-filter , backdrop-filter * motion-path , motion-offset , motion-rotation * x , y , rx , ry

finestra

  • window.scrollX , window.scrollY
  • window.innerHeight , window.innerWidth
  • window.getMatchedCSSRules() impone solo lo stile

Forme

  • inputElem.focus()
  • inputElem.select() , textareaElem.select() ( origine )

Eventi del mouse

  • mouseEvt.layerX , mouseEvt.layerY , mouseEvt.offsetX , mouseEvt.offsetY ( origine )

documento

  • doc.scrollingElement impone solo lo stile

Gamma

  • range.getClientRects() , range.getBoundingClientRect()

SVG

  • Parecchio; non ho fatto un elenco esauriente, ma la lista di layout di layout di Tony Gentilcore del 2011 ne indicava alcuni.

contenteditable

  • Un sacco di cose, … inclusa la copia di un’immagine negli appunti ( fonte )

Controlla di più qui .

Aggiornare:

robocat dai commenti

Altro background: il codice sorgente Chromium dal problema originale e una discussione su un’API performance per gli avvertimenti.

Un paio di idee:

  • Rimuovi metà del tuo codice (magari commentandolo).

    • Il problema è ancora lì? Ottimo, hai ristretto le possibilità! Ripetere.

    • Il problema non c’è? Ok, guarda la metà che hai commentato!

  • Stai usando qualsiasi sistema di controllo della versione (es. Git)? Se è così, git checkout alcuni dei tuoi commit più recenti. Quando è stato introdotto il problema? Guarda il commit per vedere esattamente quale codice è cambiato quando è arrivato il problema.

Cerca nella console di Chrome nella scheda Rete e trova gli script che impiegano più tempo a caricarsi.

Nel mio caso c’erano un set di script di aggiunta angular che avevo incluso ma non ancora utilizzato nell’app:

     

Questi erano gli unici file JavaScript che impiegavano più tempo a caricarsi del tempo specificato dall’errore “Long Running Task”.

Tutti questi file vengono eseguiti sui miei altri siti Web senza errori generati, ma stavo ricevendo questo errore “Long Run Task” su una nuova app Web che aveva a malapena qualche funzionalità. L’errore si interrompe immediatamente dopo la rimozione.

La mia ipotesi migliore è che questi componenti aggiuntivi angolari stessero guardando ricorsivamente in sezioni sempre più profonde del DOM per i loro tag di inizio: non trovando nessuno, hanno dovuto attraversare l’intero DOM prima di uscire, che ha richiesto più tempo di quanto previsto da Chrome.

1 arrivato alla console

2 Fare clic sull’icona del filtro vicino (casella di controllo “Registro di conservazione”)

3 Selezionare la casella di controllo “Nascondi violazione”


MODIFICARE

Questa funzione è stata rimossa da Chrome 58

Modificare il menu a discesa del livello di registrazione su Verbose per visualizzare le violazioni.

Potrebbe essere da Chrome 56 beta se lo si utilizza.

Ma non è sul changelog: https://blog.chromium.org/2016/12/chrome-56-beta-not-secure-warning-web.html

Puoi hide questo nella barra dei filtri della console con la casella di controllo Nascondi violazioni .

Nel mio caso, ho scoperto che questo è stato effettivamente causato da Adblock .

Ho eseguito la mia applicazione e l’ho registrata nella scheda Prestazioni in Chrome.

Qui puoi controllare varie funzioni che impiegano molto tempo per essere eseguite. Quello che è stato correlato con gli avvisi nella console proveniva da un file che è stato caricato dall’estensione di Adblock.

Controlla questi file e prova a identificare se questo è un codice di estensione o il tuo

se stai usando il canarino cromato, controlla l’opzione “Nascondi le violazioni”. Vedere qui

Ho trovato una soluzione nel codice sorgente di Apache Cordova. Implementano in questo modo:

 var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve(); var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); }; 

Semplice implementazione, ma modo intelligente.

Su Android 4.4, usa Promise . Per i browser più vecchi, usa setTimeout()


Uso:

 nextTick(function() { // your code }); 

Dopo aver inserito questo codice trucco, tutti i messaggi di avviso sono spariti.

Ho trovato la radice di questo messaggio nel mio codice. Funzionalità: ricerca che nasconde / mostra i nodes (offline). Era:

 search.addEventListener('keyup', function() { for (const node of nodes) if (node.innerText.toLowerCase().includes(this.value.toLowerCase())) node.classList.remove('hidden'); else node.classList.add('hidden'); }); 

Nella scheda Prestazioni (profiler): Riprogrammazione del ricalcolo del layore di profiler delle prestazioni del cromo

Adesso:

 search.addEventListener('keyup', function() { const nodesToHide = []; const nodesToShow = []; for (const node of nodes) if (node.innerText.toLowerCase().includes(this.value.toLowerCase())) nodesToShow.push(node); else nodesToHide.push(node); nodesToHide.forEach(node => node.classList.add('hidden')); nodesToShow.forEach(node => node.classList.remove('hidden')); }); 

Nella scheda Prestazioni (profiler): Profiler al cromo scuro

E sento che ora la ricerca funziona più velocemente (229 nodes).

Devi avere un selettore di class ripetuto che viene cercato ripetutamente da javascript. Se qualcosa dovrebbe usare un id, usalo come id, non come class. È successo a me.