2012-10-25 8 views
22

Ho appena appreso un fatto importante sull'esecuzione di javascript in caso di errore. Prima di iniziare a trarre conclusioni su questo, è meglio verificare se ho ragione.Parte JavaScript eseguita o non eseguita se lo script precedente non riesce

Data una pagina HTML di cui 2 script:

<script src="script1.js" /> 
<script src="script2.js" /> 

script1:

doSomething(); 

SCRIPT2:

doSomeOtherThing(); 

Ciò si traduce in modo efficace in un singolo script in fase di elaborazione come una sola unità:

doSomething(); 
doSomeOtherThing(); 

In particolare, se doSomething genera un errore, l'esecuzione è interrotta. 'script2' non viene mai eseguito.

Questa è la mia "Lezione 1" - si potrebbe pensare che poiché è un file incluso separatamente non è interessato da script1. Ma lo è. => vedi "ritardo aggiornamento" al di sotto


Ora, se noi cambiare SCRIPT2 come segue (presumere di essere jQuery incluso da qualche parte sopra):

$(document).ready({ doSomeOtherThing(); }); 

e posizionare lo script prima SCRIPT2:

<script src="script2.js" /> 
<script src="script1.js" /> 

L'ordine di esecuzione è efficace ancora 'doSomething()' seguita (talvolta) di 'doSomeOtherThing()'.

Tuttavia è eseguito in due "unità":

  • doSomething viene eseguito in anticipo come parte di java script del documento
  • doSomeOtherThing viene eseguito quando l'evento document.ready viene elaborato.

Se doSomeOtherThing genera un'eccezione, sarà non rompere la seconda trasformazione "unità".

(. Evito di usare il termine thread perché mi sa che tutto lo script è di solito eseguito dallo stesso filo, o più precisamente questo può dipendere dal browser)

Quindi, il mio lession 2: Anche sebbene un errore JavaScript possa impedire l'esecuzione di script successivi, non interrompe il ciclo degli eventi.


Conclusione 1

$(document).ready() fa un grande lavoro nel definire pezzi di codice JavaScript che dovrebbero essere eseguiti indipendente su tutti gli altri script nel riuscire.

O, in altre parole: se si dispone di un pezzo di JavaScript e si desidera assicurarsi che venga eseguito anche se altri script falliscono, posizionarlo all'interno di un $(document).ready().

Questo sarebbe nuovo per me in quanto avrei usato l'evento solo se lo script dipende dal caricamento completo del documento.


Conclusione 2

Facendo un ulteriore passo avanti che potrebbe essere una buona architettura decisione di avvolgere tutti script all'interno di un $(document).ready() per assicurarsi che tutti gli script sono "in coda" per l'esecuzione. Nel secondo esempio, se è stato incluso script2.jsdoposcript1.js come nell'esempio 1:

<script src="script1.js" /> 
<script src="script2.js" /> 

un errore in script1.js impedirebbe il doSomeOtherThing() da anche essere registrati, poiché la funzione $(document).ready() non sarebbe eseguita.

Tuttavia, se script1.js usati $(document).ready(), anche, che non sarebbe accaduto: sarebbero stati giustiziati

$(document).ready(function() { doSomething(); }); 
$(document).ready(function() { doSomeOtherThing(); }); 

Entrambe le linee. Successivamente, il ciclo degli eventi eseguirà doSomething, che si interromperà, ma non verrà modificato 10.

Un motivo in più per farlo sarebbe che il thread che rende la pagina possa tornare al più presto possibile e che il ciclo di eventi possa essere utilizzato per attivare l'esecuzione del codice.


Critica/Domande:

  • mi sono sbagliato?
  • Quali motivi ci sono che rendono necessario l'esecuzione di un pezzo di codice immediatamente, vale a dire non lo avvolge nell'evento?
  • Inciderebbe in modo significativo sulle prestazioni?
  • C'è un altro/modo migliore per ottenere lo stesso piuttosto che utilizzare l'evento pronto per il documento?
  • È possibile definire l'ordine di esecuzione degli script se tutti gli script registrano il loro codice come gestore di eventi? I gestori di eventi vengono eseguiti nell'ordine in cui sono stati registrati?

In attesa di eventuali commenti utili!

Aggiornamento tardiva:

Come Briguy37 rilevare correttamente, la mia osservazione deve essere stato sbagliato, in primo luogo. ("Mi sono sbagliato - sì!"). Prendendo il suo semplice esempio, posso riprodurlo in tutti i principali browser e persino in IE8, script2 viene eseguito anche se script1 genera un errore.

Ancora @ La grande risposta di Marcello consente di avere un'idea dei concetti di stack di esecuzione, ecc. Sembra proprio che ciascuno dei due script sia eseguito in uno stack di esecuzione separato.

+0

Grazie per tutte le vostre scoperte. Molto molto utile leggere +1 –

+0

@Beto - grazie per l'upvote. Sfortunatamente la mia osservazione è stata smentita. Ho aggiornato la mia domanda e la risposta accettata ora. Sentiti libero di ritirare l'upvote. – chiccodoro

+0

Ciao @chiccodoro! Ho letto il tuo post come inizio, poi ho letto tutte le risposte. Non tutte le tue scoperte erano sbagliate e mi aiutano in qualche modo a capire meglio le altre risposte che sono più tecniche. Quindi grazie comunque! –

risposta

8

Il primo presupposto che vengano eseguiti come uno script non è corretto. Script2 verrà comunque eseguito anche se Script1 genera un errore.Per un semplice test, implementare la seguente struttura di file:

-anyFolder 
--test.html 
--test.js 
--test2.js 

Il contenuto di test.html:

<html> 
    <head> 
     <script type="text/javascript" src="test.js"></script> 
     <script type="text/javascript" src="test2.js"></script> 
    </head> 
</html> 

Il contenuto di test.js:

console.log('test before'); 
throw('foo'); 
console.log('test after'); 

Il contenuto di test2 .js:

console.log('test 2'); 

Th e di uscita quando si apre test.html (nella console):

test before test.js:1 
Uncaught foo test.js:2 
test 2 

Da questo test, si può vedere che test2.js corre ancora, anche se test.js genera un errore. Tuttavia, test.js interrompe l'esecuzione dopo l'esecuzione dell'errore.

+0

È interessante. Significa forse che ho commesso un errore osservando l'esatto opposto della tua osservazione nel mio codice, o potrebbe dipendere dal browser? Dovrò dare un'occhiata più da vicino e verificarlo di nuovo. – chiccodoro

+0

@chiccodoro: Ok, fateci sapere se trovate una funzionalità diversa da qualche parte. Ho provato in IE9, Chrome e Firefox con gli stessi risultati in ciascuno. – Briguy37

+0

fatto, e esattamente come hai detto tu: script2 viene eseguito (FF, IE9). Ho verificato lo stesso comportamento quando includo i tag nella parte inferiore del corpo.Ma per la pagina piuttosto complessa che stavo prendendo le mie conclusioni da lì è incluso uno script incluso che non viene eseguito se lo script incluso prima fallisce. Strano ... – chiccodoro

2

Non sono sicuro degli errori di sintassi, ma è possibile utilizzare try {} catch(e) {} per rilevare gli errori e mantenere attivo il resto del codice.

non funzionerà fino alla fine

var json = '{"name:"John"'; // Notice the missing curly bracket } 

// This probably will throw an error, if the string is buggy 
var obj = JSON.parse(json); 

alert('This will NOT run'); 

Verrà eseguito fino alla fine

var json = '{"name:"John"'; // Notice the missing curly bracket } 

// But like this you can catch errors 
try { 
    var obj = JSON.parse(json); 
} catch (e) { 
    // Do or don' 
} 

alert('This will run'); 

UPDATE

Volevo solo mostrare come per assicurarsi che il resto del codice viene eseguito nel caso in cui il errore si verifica

Quali ragioni sono lì che rendono necessario eseguire un pezzo di codice immediatamente, vale a dire non avvolgendolo nel caso?

Performance. Ogni evento di questo tipo riempie la coda degli eventi. Non che farà molto male, ma non è proprio necessario ... Perché lavorare un po 'più tardi, se è possibile farlo adesso? Ad esempio: rilevamento e materiale del browser.

Incidere in modo significativo sulle prestazioni?

Se lo fai più volte al secondo, allora si.

C'è un altro/modo migliore per ottenere lo stesso piuttosto che utilizzare l'evento pronto per il documento ?

Sì. Vedi sopra esempio.

Può l'ordine di esecuzione di script da definire se tutti gli script solo registrare il loro codice come un gestore di eventi? I gestori di eventi sono eseguiti nell'ordine in cui sono stati registrati?

Sì, sono abbastanza sicuro che lo sono.

+0

Grazie. Presumo che i potenziali errori di entrambi i codici non siano noti in anticipo. In generale, ingoiare gli errori IMHO non sarebbe una buona idea. Preferisco farli esplodere fino a quando non vengono segnalati nella console javascript del browser. – chiccodoro

+0

Gli errori di sintassi sono comunque una storia diversa. Immagino che non avrebbero alcun effetto su altri file di script successivi. – chiccodoro

+0

@chiccodoro Si potrebbe passare l'errore alla console da 'console.log (e)'. Ma questo 'try - catch' è il modo in cui farlo. Non ascoltarmi, jQuery fa lo stesso! Leggi la fonte - vedrai. – Taai

13

Il modo in cui JS gestisce gli errori dipende dal modo in cui JS sta elaborando lo script. Non ha nulla (o poco) da fare con i thread. Perciò devi prima pensare a come JS funziona attraverso il tuo codice.

Prima di tutto JS leggerà ogni file di script/blocco in sequenza (a questo punto il tuo codice è appena visto come testo).

Than JS inizia a interpretare quei blocchi di testo e li compila in codice eseguibile. Se viene rilevato un errore di sintassi, JS interrompe la compilazione e passa allo script successivo. In questo processo JS gestisce tutti i blocchi/file di script come entità separate, ecco perché gli errori di sintassi nello script 1 non interrompono necessariamente l'esecuzione dello script 2. Il codice verrà interpretato e compilato, ma non eseguito a questo punto, quindi un throw new Error il comando non interromperà l'esecuzione.

Dopo che tutti i file di script/blocchi sono stati compilati, JS passa attraverso il codice (iniziando con il primo file di codice/blocco nel codice) e creando un cosiddetto stack di esecuzione (funzione una funzione di chiamata b chiama la funzione d ec ....) ed eseguendolo nell'ordine indicato. Se in qualsiasi momento si verifica un errore di elaborazione o viene generato a livello di programmazione (throw new Error('fail')) l'intera esecuzione di tale stack viene interrotta e JS torna all'inizio all'inizio di quello stack e inizia con l'esecuzione del successivo stack possibile.

Detto questo, la ragione per cui la funzione onload è ancora eseguito dopo un errore nel script1.js, non avviene a causa di un nuovo thread o qualcosa, è semplicemente perché un evento accumula una pila di esecuzione separato, JS può saltare a, dopo che l'errore nel precedente stack di esecuzione è accaduto.

Venendo alle tue domande:

Quali ragioni sono lì che lo rendono necessario eseguire un pezzo di codice immediatamente, vale a dire non avvolgendolo nel caso?

Ti consiglio di non avere alcun codice "immediatamente" chiamato nella tua applicazione web. La pratica migliore è quella di avere un unico punto di ingresso nella propria applicazione che si chiama all'interno di un evento onload

$(document).ready(function() {App.init()}); 

Questo non ha però nulla a che fare con la gestione degli errori o tali. La gestione degli errori in sé dovrebbe essere fatta all'interno del tuo codice con entrambi i condizionali if(typeof myValue !== 'undefined') o try/catch/finally blocks, dove potresti aspettarti potenziali errori.Questo ti dà anche la possibilità di provare una seconda via all'interno del blocco catch o gestire con grazia l'errore infine.

Se è possibile creare l'evento guidato dell'applicazione (ovviamente non per motivi di gestione degli errori), farlo. JS è un linguaggio basato su eventi e puoi sfruttarlo al massimo quando scrivi un codice basato su eventi ...

Incidere in modo significativo sulle prestazioni?

Un approccio guidato da eventi IMHO renderebbe la vostra applicazione ancora più performante e più solida allo stesso tempo. Il codice basato sugli eventi può aiutarti a ridurre la quantità di logica di elaborazione interna, devi solo inserirla.

C'è un altro/modo migliore per ottenere lo stesso piuttosto che utilizzare l'evento pronto per il documento?

Come prima accennato: try/catch/finally

Può l'ordine di esecuzione di script da definire se tutti gli script basta registrare il loro codice come un gestore di eventi? I gestori di eventi vengono eseguiti nell'ordine in cui sono stati registrati?

Se si registra lo stesso evento sullo stesso oggetto, l'ordine viene mantenuto.

+0

Grazie, Marcello! Per quanto riguarda le "sottocatene", puoi elaborarle? Come posso creare una sottocatena che viene eseguita anche se la sottocatena precedente genera un'eccezione? Ti riferisci all'utilizzo di "try-catch"? – chiccodoro

+0

Per quanto riguarda le prestazioni, ciò conferma quello che penserei anch'io, anche se, un semplice pezzo di codice eseguito con il sovraccarico di registrazione ed elaborazione di un evento anziché eseguirlo direttamente probabilmente aggiunge un po 'di tempo in più per l'esecuzione - ma può essere fatto in modo asincrono (o almeno successivamente) a turno – chiccodoro

+0

@chiccodoro Ho dovuto correggere alcune parti, poiché erano fuorvianti. Innanzitutto non è una catena di exec, è una pila. In secondo luogo ci sono solo 3 modi per costruire uno "sub" o uno stack distaccato: setTimeout, Events ed eval, non dipende dal layout del codice come sottinteso dalla mia risposta. Ecco un buon link sugli stack in JS: http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/ –

Problemi correlati