Slide 1

Slide 1 text

THE SORRY STATE OF JAVASCRIPT ERROR HANDLING By ( ), 2015-06-18 Dominykas Blyžė @dymonaz

Slide 2

Slide 2 text

INWH.SE/WIN

Slide 3

Slide 3 text

> t h r o w T a b l e ノಠ益ಠノ彡┻━┻ > THROW ALL THE THINGS! But then what?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

IN THE BROWSER WORLD... Old browsers 3rd party scripts Browser extensions Cross-domain restrictions

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

IN THE BROWSER WORLD... Network errors Aggressive caching Random obscure

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

LOGGING FROM THE BROWSER

Slide 13

Slide 13 text

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 } ) ; } ;

Slide 14

Slide 14 text

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 ) ;

Slide 15

Slide 15 text

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 '

Slide 16

Slide 16 text

TRY At the very least they have useful blogs. Rollbar Errorception

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

CATCHING ERRORS

Slide 19

Slide 19 text

TRY/CATCH Ugly Sync Deoptimizes * * no big deal most of the time, but still

Slide 20

Slide 20 text

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.

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

MEANWHILE AT W3C...

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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 " >

Slide 26

Slide 26 text

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 * / }

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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 }

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

THROWING ERRORS

Slide 31

Slide 31 text

THROW ERRORS If you don't throw, it won't have a stack in IE

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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 ;

Slide 34

Slide 34 text

THROW CUSTOM ERRORS I don't want to talk about it...

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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 ) ;

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

< / ノಠ益ಠノ彡┻━┻ > Slides: dominykas.net/25 We're hiring: inwh.se/win @dymonaz ;