Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The sorry state of Javascript error handling

The sorry state of Javascript error handling

Dominykas Blyžė

June 18, 2015
Tweet

More Decks by Dominykas Blyžė

Other Decks in Programming

Transcript

  1. THE SORRY STATE OF JAVASCRIPT ERROR HANDLING By ( ),

    2015-06-18 Dominykas Blyžė @dymonaz
  2. > t h r o w T a b l

    e ノಠ益ಠノ彡┻━┻ > THROW ALL THE THINGS! But then what?
  3. JAVASCRIPT IS 20. READY FOR PRODUCTION. Seriously, browse the web

    with the developer tools console open logging errors and be truly amazed that the internet ever worked. @shanselman
  4. HANDLE ALL THE THINGS? 92% of catastrophic failures are the

    result of incorrect error handling Simple Testing Can Prevent Most Critical Failures by Ding Yuan et al, dominykas.net/24
  5. PRO-TIP Make sure stuff works without JS: Use real <

    a h r e f > with real URLs Use real forms with real buttons p r e v e n t D e f a u l t ( ) as a last thing
  6. ERROR HANDLING IN THE NORMAL WORLD 1. Stay aware of

    errors 2. Provide detailed error information 3. Add exception handling code 4. If all else fails - crash with a dump
  7. IN THE BROWSER WORLD... t h r o w n

    e w E r r o r vs t h r o w o l d _ T a b l e Errors in async functions Errors in callbacks Zalgo
  8. RANDOM OBSCURE XHR randomly status 0 (but error logged CORS

    XHR) < i f r a m e i d = " l o c a l S t o r a g e " / > l o c a l S t o r a g e max size is 0 in private mode on iOS g e t C o m p u t e d S t y l e stops being a function... Random m e s s a g e events from plugins
  9. DO THIS TOMORROW If you're not doing it yet w

    i n d o w . o n e r r o r = f u n c t i o n ( e r r , u r l , l i n e ) { g a ( ' s e n d ' , ' e x c e p t i o n ' , { ' e x D e s c r i p t i o n ' : l i n e + " " + e r r } ) ; } ;
  10. DO THIS NEXT WEEK Set up a proper logging endpoint

    Version your releases and pass on the version Make sure versions match across different bundles Don't include "data" inside the "message", i.e. l o g ( m e s s a g e S t r i n g , o b j D a t a ) ;
  11. PAY ATTENTION Anything can be thrown - must be able

    to serialize correctly. v a r l o g M e s s a g e = e r r & & e r r . m e s s a g e ? e r r . m e s s a g e : " " + e r r ; > n u l l . t o S t r i n g ( ) T y p e E r r o r : C a n n o t r e a d p r o p e r t y ' t o S t r i n g ' o f n u l l > n e w E r r o r ( " D a m n i t " ) . t o S t r i n g ( ) ' E r r o r : D a m n i t ' > n e w E r r o r ( " D a m n i t " ) . m e s s a g e ' D a m n i t '
  12. DREAM C o n t e n t - S

    e c u r i t y - P o l i c y : s t y l e - s r c c d n . e x a m p l e . c o m ; r e p o r t - u r i / _ / c s p - r e p o r t s
  13. GUARD() f u n c t i o n g

    u a r d ( f n ) { r e t u r n f u n c t i o n ( ) { t r y { r e t u r n f n . a p p l y ( t h i s , a r g u m e n t s ) ; } c a t c h ( e r r ) { l o g E r r o r ( e r r ) ; t h r o w e r r ; } } ; } Using this for auto-wrapping is probably a bad idea.
  14. USE PROMISES Wrap promise construction Reject with n e w

    E r r o r ( ) Don't forget to . c a t c h ( l o g A n d R e t h r o w ) Stack traces an issue (unless native) New: u n h a n d l e d R e j e c t i o n Problem: UI can't have a break in event loop
  15. WINDOW.ONERROR m s g is different on every browser Yay!

    Uncaught Error: undefined is not an object u r l has cross-domain restrictions l i n e n o is 1, because you minified c o l n o is fairly recent e r r o r O b j is very recent
  16. WINDOW.ONERROR Not the same as a d d E v

    e n t L i s t e n e r ( ' e r r o r ' ) TraceKit for stacks, if you can afford it Run your code in an iframe, if on a third party site r e t u r n t r u e if handled
  17. WINDOW.ONERROR - CORS 1. A c c e s s

    - C o n t r o l - A l l o w - O r i g i n : * 2. < s c r i p t c r o s s o r i g i n = " a n o n y m o u s " >
  18. WINDOW.ONERROR - CORS The script can inject itself with the

    attribute set s e t A t t r i b u t e ( " c r o s s o r i g i n " ) , not s c r i p t . c r o s s o r i g i n i f ( ! d o c u m e n t . c u r r e n t S c r i p t . g e t A t t r i b u t e ( " c r o s s o r i g i n " ) ) { v a r s c r i p t = d o c u m e n t . c r e a t e E l e m e n t ( " s c r i p t " ) ; s c r i p t . s r c = d o c u m e n t . c u r r e n t S c r i p t . s r c ; s c r i p t . s e t A t t r i b u t e ( " c r o s s o r i g i n " , " a n o n y m o u s " ) ; d o c u m e n t . h e a d . a p p e n d C h i l d ( s c r i p t ) ; } e l s e { / * p r o c e e d * / }
  19. SOURCE MAPS b r o w s e r i

    f y \ - e b u n d l e / e n t r y . j s \ - t u g l i f y i f y \ - d | e x o r c i s t b u n d l e . j s . m a p > b u n d l e . j s
  20. SOURCE MAPS v a r S o u r c

    e M a p C o n s u m e r = r e q u i r e ( " s o u r c e - m a p " ) . S o u r c e M a p C o n s u m e r ; v a r m a p = J S O N . p a r s e ( f s . r e a d F i l e S y n c ( " b u n d l e . j s . m a p " ) ) ; v a r s m c = n e w S o u r c e M a p C o n s u m e r ( m a p ) ; c o n s o l e . l o g ( s m c . o r i g i n a l P o s i t i o n F o r ( { l i n e : 5 , c o l u m n : 3 3 } ) ) ; OUTPUT { s o u r c e : ' ~ / b u n d l e / s t u f f . j s ' , l i n e : 2 , c o l u m n : 7 , n a m e : n u l l }
  21. EMBULACT $ e x c e p t i o

    n H a n d l e r o n e r r o r Replay events
  22. THROW ERRORS If it's not an error, it won't have

    a stack This applies to n o d e b a c k ( e r r , d a t a ) O b j e c t . c r e a t e ( E r r o r ) is not an error
  23. USE ERROR CODES v a r e r r o

    r = n e w E r r o r ( " s n a p . . . " ) ; e r r o r . c o d e = " E _ S N A P " ; t h r o w e r r o r ;
  24. THROW CUSTOM ERRORS M y C u s t o

    m E r r o r should: Keep m e s s a g e as a first param Have a m e s s a g e property Have a n a m e = " M y C u s t o m E r r o r " property Extend E r r o r (i.e. support i n s t a n c e o f ) Work with and without n e w
  25. ADD USEFUL INFO Good custom errors also should: Have a

    reasonable t o S t r i n g Be able to wrap around existing errors Have a stack trace
  26. POOR MAN'S S T A C K T R A

    C E - J S f u n c t i o n C u s t o m E r r o r ( m e s s a g e ) { v a r t e m p = E r r o r . c a l l ( t h i s , m e s s a g e ) ; t e m p . n a m e = t h i s . n a m e = ' C u s t o m E r r o r ' ; t r y { t h r o w t e m p ; } c a t c h ( a f t e r T h r o w ) { t h i s . s t a c k = a f t e r T h r o w . s t a c k ; } t h i s . m e s s a g e = t e m p . m e s s a g e ; } C u s t o m E r r o r . p r o t o t y p e = O b j e c t . c r e a t e ( E r r o r . p r o t o t y p e ) ;
  27. NUMBER OF BORING S T A C K LINES In

    Blink: name/message + 2 In Webkit: 1 In Firefox: 1 In IE: name/message + 1