2013-05-24 7 views
6

Ogni volta che si verifica un errore all'interno di un gestore eventi, l'esecuzione del codice viene interrotta completamente in modo che non venga richiamata la seconda chiamata all'evento.L'errore Javascript interrompe l'esecuzione del codice

Ad esempio:

$(function() { 
    window.thisDoesntExist(); 
} 
$(function() { 
    //Do something unharmful and unrelated to the first event 
} 

si può facilmente risolvere il problema in questo esempio (semplificato) con l'aggiunta di try/catch in entrambe le funzioni anonime, ma in realtà queste funzioni spesso aggiungere molti altri gestori di eventi che a sua volta richiederebbe prova/cattura. Finisco con codice molto ripetitivo riempito con blocchi try/catch.

I miei progetti hanno un design modulare in cui ogni funzionalità si trova in un JS diverso (e viene concatenata durante un processo di compilazione). Sto cercando un modo più generico per gestire gli errori all'interno di ogni funzione in modo che l'errore non fermi l'esecuzione del codice delle altre funzionalità.

Ho già provato seguenti soluzioni: - window.onerror (anche se si torna vero in questa funzione, l'esecuzione di codice viene interrotta) - $ (window) .error() => deprecato e l'esecuzione di codice si ferma

+0

Hai letto la mia domanda? Puoi facilmente risolvere il problema in questo esempio (semplificato) aggiungendo try/catch in entrambe le funzioni anonime, ma in realtà queste funzioni spesso aggiungono molti altri gestori di eventi che a loro volta richiederebbero try/catch. Finisco con codice molto ripetitivo riempito con blocchi try/catch. – Webberig

+0

Beh, forse questo è il compromesso che devi fare se vuoi che il tuo codice sia il più robusto possibile. – CBroe

+0

@Webberig, certo che lo so. Il requisito di base di cui hai bisogno è di continuare ad eseguire il codice su (qualsiasi) errore. L'unico modo è usare try catch. È il primo passo. Successivamente, è possibile utilizzare una richiamata di errore o emettere un evento di errore o qualsiasi altra cosa per rendere la gestione degli errori solida e flessibile. Puoi riferirti al codice sorgente di Requirejs, usa anche il try catch. https://github.com/jrburke/requirejs/blob/master/require.js –

risposta

-2

Ho trovato una soluzione. Quando si utilizza setTimeout, il codice viene eseguito in un thread separato, pertanto non interromperà altre parti della pagina Web.

$(function() { 
    setTimeout(function() { 
    window.thisDoesntExist(); 
    }, 0); 
}); 
$(function() { 
    setTimeout(function() { 
     //Do something unharmful and unrelated to the first event 
     alert("This passes") 
    }, 0); 
}); 

In questo esempio, viene eseguita la seconda funzione, anche quando il primo genera un errore. Ecco un esempio di lavoro: http://jsfiddle.net/mathieumaes/uaEsy/

+1

+1 perché ho appreso qualcosa -1 perché si tratta di un hack grossissimo – mpd

+2

La funzione di riferimento setTimout non funziona in un thread separato. Lo stack di esecuzione di un runtime JavaScript è a thread singolo. Quello che succede in realtà è che quando il tuo errore viene gestito dal tuo call di onerror, lo stack di esecuzione viene cancellato (ecco perché nessun codice aggiuntivo viene eseguito dopo il tuo errore).setTimeout fa in modo che la funzione di riferimento venga inserita nella coda degli eventi e gli eventi in quella coda vengano eseguiti quando lo stack di esecuzione è libero. Funziona, ma non a causa del multi-threading. – user1739635

+0

Inoltre, l'ordine non è garantito durante l'esecuzione asincrona, dipende dall'implementazione, se tali attività devono avvenire in sequenza, verrà creata una condizione di competizione. Presumo dal contesto che l'ordine non abbia importanza qui ma come soluzione generale questo è problematico. – guioconnor

5

È possibile creare una funzione di supporto per evitare la duplicazione dello stesso codice di caldaia.

function tryFunction(f, onerror) { 
    try { 
     if (typeof f == 'function') { 
      return f(); 
     } 
    } catch (e) { 
     return onerror(e); 
    } 
} 

$(function() { 
    var result = tryFunction(window.thisDoesNotExist, function (error) { 
     alert('Whoops: ' + error); 
    }); 
}); 

I created a little demonstration. È leggermente diverso ma la stessa idea.

0

Si può semplicemente chiamare if (typeof myFunction == 'function') prima di chiamare myFunction()

e, facoltativamente, avvolgerlo in una funzione generica come detto da Bart di avere la possibilità di registrare un errore nella console se la funzione non esiste.

Se la tua webapp è enorme con molte interazioni e JS, troppe try catch potrebbero alterare le prestazioni globali della tua applicazione.

0

vorrei provare qualcosa di simile con un wrapper che gestirà il tentativo di cattura per voi (vedi sotto, o di questo jsfiddle: http://jsfiddle.net/TVfCj/2/)

Dal modo in cui io sono (non, e non realmente) la gestione della questo e gli argomenti, immagino sia ovvio che sto iniziando con js. Ma spero che tu abbia ottenuto l'idea, ed è corretto/utile.

var wrapper = { 
     wrap: function wrap(f) { 
      return function (args) { 
       try { 
        f.apply(null, args); 
       } catch (ex){ 
        console.log(f.name+" crashed with args "+args); 
       }; 
      }; 
     } 
    }; 

    var f1 = function f1Crashes(arg) { 
     return window.thisDoesntExist(); 
    }; 
    var f2 = function f2Crashes(arg) { 
     return window.thisDoesntExist(); 
    }; 

    var f3 = function f3MustNotCrash(arg) { 
     wrapper.wrap(f1)(arg); 
     wrapper.wrap(f2)(arg); 
    } 

    f3('myarg'); 
0

Il try - modello catch si menzionare il tentativo nella tua domanda è il modo corretto - si desideratry - catch blocchi, non un modo per silenziosamente camion attraverso errori dell'unità (in generale sempre essere estremamente attenti a gestire le eccezioni a livello globale e continuando, in questo modo si trovano bug di corruzione dei dati che si trovano solo 6 mesi dopo).

Il tuo vero problema è questo:

... in realtà queste funzioni spesso aggiungere vari altri gestori di eventi che a sua volta richiederebbe try/catch. Finisco con codice molto ripetitivo riempito con blocchi try/catch.

La correzione è Promise. Si tratta di una nuova struttura, nativa nella maggior parte dei browser, ma facilmente trasponibile in quelle lente (ahem, IE), che offre un modo standard di gestire sia la callback dell'evento che l'eccezione dall'evento.

Con un codice Promise, il tuo codice promette di fare sempre qualcosa: risoluzione/esito positivo o rifiuto/esito negativo.

function moduleA() { 
    return new Promise(function (resolve, reject) 
    { 
     try{ 
      var result = window.thisDoesntExist(); 
      resolve(resolve); // Success! 
     } 
     catch(err){ 
      reject(err); // Fail! 
     } 
    }); 
} 

questo è meglio perché anziché nido try - catch blocchi in ogni richiamata È possibile invece che le promesse della catena:

moduleA(). 
    then(moduleB). 
    then(moduleC). 
    catch(errorHandler); // Catch any error from A, B, or C 

È possibile anche gestire un errore e continuare:

moduleA(). 
    catch(continuableErrorHandler). // Catch any error from A 
    then(moduleB). 
    then(moduleC). 
    catch(errorHandler); // Catch any error from B or C 

Avrai ancora bisogno di un sacco di try - catch blocchi nei callback, ma tutto ciò che è stato inserito in un Promise possono essere trattati nello stesso modo modulare.

Disponibile in JS è async e await, ma ora è possibile utilizzarli con un traspolatore. Questi usi promettono di creare codice che è molto più facile da leggere e, soprattutto, (per te) hanno un singolo try - catch in alto che raccoglie eccezioni dall'intera catena Promise.

Questa risposta è già troppo lunga, ma ho blogged about that in more detail.

TL; DR: Se il problema è "[callback evento] il codice molto ripetitivo farcita con blocchi try/catch" provare a utilizzare Promise invece.

Problemi correlati