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

GopherJS

 GopherJS

Timo Savola

May 11, 2016
Tweet

More Decks by Timo Savola

Other Decks in Programming

Transcript

  1. Go & Me 2009: Go is released 2009 or 2010:

    "7.5% time" project at Sulake using Go 2010: First (and only) contribution to Go 2011: IRC-Galleria uses Go in production 2011: Early Ninchat prototype in pure Go 2012: Ninchat uses Go among other languages 2014: Ninchat uses GopherJS
  2. GopherJS A compiler from Go to JavaScript Supports browsers and

    Node.js Started in 2013 By Richard Musiol g o g e t g i t h u b . c o m / g o p h e r j s / g o p h e r j s g o p h e r j s b u i l d
  3. Standard packages Fully supported: 110 Partially supported: 12 n e

    t / h t t p o s and s y s c a l l supported on Node.js Not supported: 21 u n s a f e
  4. Goroutines are supported Local variables are stored in closures When

    a something blocks, the call stack is unwound When a goroutine is resumed, its call stack and closures are restored
  5. Access the JavaScript world p a c k a g

    e m a i n i m p o r t " g i t h u b . c o m / g o p h e r j s / g o p h e r j s / j s " v a r d o c = j s . G l o b a l . G e t ( " d o c u m e n t " ) f u n c m a i n ( ) { d i v : = d o c . C a l l ( " c r e a t e E l e m e n t " , " d i v " ) d i v . S e t ( " i n n e r T e x t " , " h e l l o w o r l d " ) d o c . G e t ( " b o d y " ) . C a l l ( " a p p e n d C h i l d " , d i v ) }
  6. Export objects to the JavaScript world, part 1 c o

    n s t M y S t r i n g = " h e l l o w o r l d " f u n c M y A p p l y F u n c ( c a l l a b l e * j s . O b j e c t , a r g s t r i n g ) { i f c a l l a b l e ! = j s . U n d e f i n e d { c a l l a b l e . I n v o k e ( a r g ) } } f u n c m a i n ( ) { j s . G l o b a l . G e t ( " w i n d o w " ) . S e t ( " M y S t u f f " , m a p [ s t r i n g ] i n t e r f a c e { } { " M Y _ S T R I N G " : M y S t r i n g , " m y A p p l y F u n c " : M y A p p l y F u n c , } ) } > M y S t u f f . m y A p p l y F u n c ( s o m e U n a r y F u n c t i o n , " a s d f " )
  7. Export objects to the JavaScript world, part 2 t y

    p e V a l u e T h i n g s t r u c t { F o o i n t B a r s t r i n g B a z [ ] u i n t 1 6 } f u n c N e w V a l u e T h i n g ( ) * V a l u e T h i n g { r e t u r n & V a l u e T h i n g { } } f u n c ( t * V a l u e T h i n g ) G e t S o m e t h i n g ( ) i n t { r e t u r n 4 2 } > t = e x a m p l e s . N e w V a l u e T h i n g ( ) > t O b j e c t { F o o : 0 , B a r : " " , B a z : A r r a y [ 0 ] } > t . G e t S o m e t h i n g ( ) Uncaught TypeError: t.GetSomething is not a function
  8. Export objects to the JavaScript world, part 3 t y

    p e A c t i v e T h i n g s t r u c t { F o o i n t B a r s t r i n g B a z [ ] u i n t 1 6 } f u n c N e w A c t i v e T h i n g ( ) * j s . O b j e c t { r e t u r n j s . M a k e W r a p p e r ( & A c t i v e T h i n g { } ) } f u n c ( t * A c t i v e T h i n g ) G e t S o m e t h i n g ( ) i n t { r e t u r n 4 2 } > t = e x a m p l e s . N e w A c t i v e T h i n g ( ) > t O b j e c t { i n t e r n a l s t u f f o n l y } > t . G e t S o m e t h i n g ( ) 4 2
  9. Goroutine gotcha Doesn't work: i m p o r t

    " n e t / h t t p " f u n c M y E x p o r t e d F u n c 1 ( u r l s t r i n g ) { r , _ : = h t t p . G e t ( u r l ) / / b l o c k i n g c a l l p r i n t l n ( r ) } Works: i m p o r t " n e t / h t t p " f u n c M y E x p o r t e d F u n c 2 ( u r l s t r i n g ) { g o f u n c ( ) { r , _ : = h t t p . G e t ( u r l ) / / b l o c k i n g c a l l p r i n t l n ( r ) } ( ) }
  10. GOARCH is "js" m y c o d e _

    j s . g o / / + b u i l d j s i m p o r t " g i t h u b . c o m / g o p h e r j s / g o p h e r j s / j s " f u n c D i s p l a y ( m e s s a g e s t r i n g ) { j s . G l o b a l . G e t ( " c o n s o l e " ) . C a l l ( " l o g " , m e s s a g e ) } m y c o d e _ d e f a u l t . g o / / + b u i l d ! j s i m p o r t " f m t " i m p o r t " o s " f u n c D i s p l a y ( m e s s a g e s t r i n g ) { f m t . F p r i n t l n ( o s . S t d e r r , m e s s a g e ) }
  11. File sizes Empty main function: 50 KB mini ed 12

    KB mini ed and gzipped Import the s o r t package: 51 KB mini ed 12 KB mini ed and gzipped Import the f m t package: 392 KB 77 KB gzipped
  12. NinchatClient Low-level API client implemented in GopherJS Robust I/O state

    machine thanks to goroutines Avoid bloat by using the browser's APIs directly Supports IE8+ with shims (and stubs for typed array types) Same code base supports also native Go h t t p s : / / g i t h u b . c o m / n i n c h a t / n i n c h a t - g o is an importable Go package h t t p s : / / g i t h u b . c o m / n i n c h a t / n i n c h a t - j s is the main package
  13. NinchatClient cont'd Code base: 65% common code 22% GopherJS wrapper

    code 13% native Go wrapper code (for custom abstractions) File size: 157 KB mini ed 30 KB mini ed and gzipped Estimated le size without direct browser API calls: 3 MB mini ed 600 KB mini ed and gzipped
  14. Performance Ninchat pro ling: Object conversion between JS and Go

    worlds takes time UI framework etc. take up most of the time anyway Internet says: "Performance is quite good in most cases" Microbenchmarks may be 1000x slower than native Go ...or they may be faster, thanks to V8
  15. Conclusion Don't use anything that imports the f m t

    package (etc.) if le size matters Mapping complicated Go APIs to JavaScript is complicated As for running Go code in the browser: it just works! Goroutines, channels and static typing bring their bene ts if a reasonably self- contained part of your application is implemented in Go