The sorry state of Javascript error handling

The sorry state of Javascript error handling

760ee07e2a7c2a05ac35a981276c6a29?s=128

Dominykas Blyžė

June 18, 2015
Tweet

Transcript

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

    2015-06-18 Dominykas Blyžė @dymonaz
  2. INWH.SE/WIN

  3. > t h r o w T a b l

    e ノಠ益ಠノ彡┻━┻ > THROW ALL THE THINGS! But then what?
  4. 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
  5. 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
  6. 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
  7. 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
  8. IN THE BROWSER WORLD... Old browsers 3rd party scripts Browser

    extensions Cross-domain restrictions
  9. 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
  10. IN THE BROWSER WORLD... Network errors Aggressive caching Random obscure

  11. 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
  12. LOGGING FROM THE BROWSER

  13. 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 } ) ; } ;
  14. 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 ) ;
  15. 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 '
  16. TRY At the very least they have useful blogs. Rollbar

    Errorception
  17. 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
  18. CATCHING ERRORS

  19. TRY/CATCH Ugly Sync Deoptimizes * * no big deal most

    of the time, but still
  20. 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.
  21. 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
  22. 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
  23. MEANWHILE AT W3C...

  24. 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
  25. 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 " >
  26. 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 * / }
  27. 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
  28. 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 }
  29. 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
  30. THROWING ERRORS

  31. THROW ERRORS If you don't throw, it won't have a

    stack in IE
  32. 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
  33. 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 ;
  34. THROW CUSTOM ERRORS I don't want to talk about it...

  35. 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
  36. 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
  37. 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 ) ;
  38. 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
  39. < / ノಠ益ಠノ彡┻━┻ > Slides: dominykas.net/25 We're hiring: inwh.se/win @dymonaz

    ;