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

Yield! How ES6 Generators and Monocle-js Can Bring Async Into Line, Literally

Yield! How ES6 Generators and Monocle-js Can Bring Async Into Line, Literally

"Callback hell" is an oft-bemoaned state of Javascript programs. Some developers have seen their code trapped in its Ninth Circle and have lost all hope of getting it out. Others are callback agnostics and don't believe this so-called hell even exists. And most of us are probably somewhere in between: working in that pyramid-shaped purgatory where, we think, if we do our Good Parts penitence, we will eventually get our code to the heaven of Readability and Maintainability.

While smart practices and async helpers can limit the pain of callback-based control flow, ES6 generators make possible new approaches that result in code which is much easier to read, maintain, and reason about. Monocle-js is one such project. In this talk, we'll look at some of the control flow situations which are particularly ugly in callback-based approaches, then discuss ES6's new generator support and `yield` keyword. With a basic understanding of generators in hand, we'll explore how Monocle-js can drag the aforementioned examples out of callback purgatory and set them on the straight and narrow path to Readability and Maintainability.

Jonathan Lipps

May 10, 2014
Tweet

More Decks by Jonathan Lipps

Other Decks in Programming

Transcript

  1. Yield!
    Or, How ES6 Generators and Monocle-js Can
    Bring Async Into Line, Literally
    ScotlandJS • Edinburgh • 5/10/2014
    #sjsJonathanL
    Jonathan Lipps • Director of Ecosystem & Integrations • Sauce Labs
    @jlipps • @saucelabs

    View Slide

  2. #sjsJonathanL
    Jonathan Lipps • Director of Ecosystem & Integrations • Sauce Labs
    @jlipps • @saucelabs
    Ecosystem &
    Integrations

    View Slide

  3. “Asynchronous Control Flow”
    #sjsJonathanL
    @jlipps

    View Slide

  4. Sync
    #sjsJonathanL
    @jlipps
    Async

    View Slide

  5. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking

    View Slide

  6. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution

    View Slide

  7. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution
    Result captured by assignment

    View Slide

  8. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution
    Result captured by assignment
    Errors handled with try/catch

    View Slide

  9. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution
    Non-blocking
    Result captured by assignment
    Errors handled with try/catch

    View Slide

  10. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution
    Non-blocking
    Result captured by assignment
    Errors handled with try/catch
    Deferred execution

    View Slide

  11. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution
    Non-blocking
    Result captured by assignment
    Errors handled with try/catch
    Deferred execution
    Result captured in callback

    View Slide

  12. Sync
    #sjsJonathanL
    @jlipps
    Async
    Blocking
    Immediate execution
    Non-blocking
    Result captured by assignment
    Errors handled with try/catch
    Deferred execution
    Result captured in callback
    Errors handled in callback

    View Slide

  13. Sync Async
    #sjsJonathanL
    @jlipps

    View Slide

  14. Sync Async
    #sjsJonathanL
    @jlipps

    View Slide

  15. Sync Async
    #sjsJonathanL
    @jlipps

    View Slide

  16. Control Flow is how you structure logical
    dependencies between statements in your
    programs
    #sjsJonathanL
    @jlipps

    View Slide

  17. Control Statements are familiar bits of
    JavaScript, usually learned easily and early on
    #sjsJonathanL
    @jlipps

    View Slide

  18. #sjsJonathanL
    @jlipps

    View Slide

  19. if
    #sjsJonathanL
    @jlipps

    View Slide

  20. if
    then
    #sjsJonathanL
    @jlipps

    View Slide

  21. if
    then
    for
    #sjsJonathanL
    @jlipps

    View Slide

  22. if
    then
    for
    while
    #sjsJonathanL
    @jlipps

    View Slide

  23. if
    then
    for
    while
    do
    #sjsJonathanL
    @jlipps

    View Slide

  24. if
    then
    for
    while
    do
    try
    #sjsJonathanL
    @jlipps

    View Slide

  25. if
    then
    for
    while
    do
    try
    catch
    #sjsJonathanL
    @jlipps

    View Slide

  26. if
    then
    for
    while
    do
    try
    catch
    switch
    #sjsJonathanL
    @jlipps

    View Slide

  27. if
    then
    for
    while
    do
    try
    catch
    switch
    break
    #sjsJonathanL
    @jlipps

    View Slide

  28. if
    then
    for
    while
    do
    try
    catch
    switch
    break
    continue
    #sjsJonathanL
    @jlipps

    View Slide

  29. if
    then
    for
    while
    do
    try
    catch
    switch
    break
    continue
    return
    #sjsJonathanL
    @jlipps

    View Slide

  30. #sjsJonathanL
    @jlipps

    View Slide

  31. #sjsJonathanL
    @jlipps

    View Slide

  32. #sjsJonathanL
    @jlipps

    View Slide

  33. #sjsJonathanL
    @jlipps

    View Slide

  34. #sjsJonathanL
    @jlipps

    View Slide

  35. #sjsJonathanL
    @jlipps

    View Slide

  36. x = 1
    #sjsJonathanL
    @jlipps

    View Slide

  37. x = 1
    y = x + 2
    #sjsJonathanL
    @jlipps

    View Slide

  38. x = 1
    y = x + 2
    y < x
    #sjsJonathanL
    @jlipps

    View Slide

  39. x = 1
    y = x + 2
    y < x
    y++ y--
    #sjsJonathanL
    @jlipps

    View Slide

  40. x = 1
    y = x + 2
    y < x
    y++ y--
    x++
    #sjsJonathanL
    @jlipps

    View Slide

  41. Sync control ow is easy
    #sjsJonathanL
    @jlipps

    View Slide

  42. Async control ow can be tricky when there
    are dependencies between methods
    #sjsJonathanL
    @jlipps

    View Slide

  43. assignXY()
    y < x
    incrementY() decrementY()
    incrementX()
    #sjsJonathanL
    @jlipps

    View Slide

  44. assignXY()
    y < x
    incrementY() decrementY()
    incrementX()
    #sjsJonathanL
    @jlipps

    View Slide

  45. assignXY()
    y < x
    incrementY() decrementY()
    incrementX()
    ?
    #sjsJonathanL
    @jlipps

    View Slide

  46. assignXY()
    y < x
    incrementY() decrementY()
    incrementX()
    #sjsJonathanL
    @jlipps

    View Slide

  47. assignXY()
    y < x
    incrementY() decrementY()
    incrementX()
    #sjsJonathanL
    @jlipps

    View Slide

  48. The trouble with callbacks
    #sjsJonathanL
    @jlipps

    View Slide

  49. 1. Visual unreadability / “Pyramid effect”
    #sjsJonathanL
    @jlipps

    View Slide

  50. #sjsJonathanL
    @jlipps

    View Slide

  51. 1. Visual unreadability / “Pyramid effect”
    2. Error handling
    #sjsJonathanL
    @jlipps

    View Slide

  52. #sjsJonathanL
    @jlipps

    View Slide

  53. #sjsJonathanL
    @jlipps

    View Slide

  54. :-(
    #sjsJonathanL
    @jlipps

    View Slide

  55. 1. Visual unreadability / “Pyramid effect”
    2. Error handling
    3. Control ow: conditionals
    #sjsJonathanL
    @jlipps

    View Slide

  56. #sjsJonathanL
    @jlipps

    View Slide

  57. #sjsJonathanL
    @jlipps

    View Slide

  58. Obscuring
    functionality
    #sjsJonathanL
    @jlipps

    View Slide

  59. Need to remember
    to return
    #sjsJonathanL
    @jlipps

    View Slide

  60. 1. Visual unreadability / “Pyramid effect”
    2. Error handling
    3. Control ow: conditionals
    4. Control ow: loops
    #sjsJonathanL
    @jlipps

    View Slide

  61. #sjsJonathanL
    @jlipps

    View Slide

  62. #sjsJonathanL
    @jlipps

    View Slide

  63. Checking
    conditions
    #sjsJonathanL
    @jlipps

    View Slide

  64. So Recursion!
    Much functional!
    #sjsJonathanL
    @jlipps

    View Slide

  65. Async control ow with callbacks involves lots
    of boilerplate. We can haz framework?
    #sjsJonathanL
    @jlipps

    View Slide

  66. https://github.com/caolan/async
    #sjsJonathanL
    @jlipps

    View Slide

  67. async.series
    #sjsJonathanL
    @jlipps

    View Slide

  68. async.eachSeries
    async.series
    #sjsJonathanL
    @jlipps

    View Slide

  69. async.eachSeries
    async.whilst
    async.series
    #sjsJonathanL
    @jlipps

    View Slide

  70. async.eachSeries
    async.whilst
    async.until
    async.series
    #sjsJonathanL
    @jlipps

    View Slide

  71. async.eachSeries
    async.whilst
    async.until
    async.series ;
    #sjsJonathanL
    @jlipps

    View Slide

  72. async.eachSeries
    async.whilst
    async.until
    async.series
    for
    ;
    #sjsJonathanL
    @jlipps

    View Slide

  73. async.eachSeries
    async.whilst
    async.until
    async.series
    for
    while
    ;
    #sjsJonathanL
    @jlipps

    View Slide

  74. async.eachSeries
    async.whilst
    async.until
    async.series
    for
    while
    while !
    ;
    #sjsJonathanL
    @jlipps

    View Slide

  75. Callback-based control ow strategies can be
    at best a clean re-implementation of JS’s own
    control statements. Can we do better?
    #sjsJonathanL
    @jlipps

    View Slide

  76. What do generators have to do
    with any of this?
    #sjsJonathanL
    @jlipps

    View Slide

  77. Generators are a new ES6 feature available in
    node 11 and up, by passing the --harmony ag
    to node
    #sjsJonathanL
    @jlipps

    View Slide

  78. Generators allow lazy construction of
    potentially in nite sequences
    #sjsJonathanL
    @jlipps

    View Slide

  79. Code in generators can also respond to behavior
    in the outside world! They do this with the new
    yield keyword.
    #sjsJonathanL
    @jlipps

    View Slide

  80. #sjsJonathanL
    @jlipps

    View Slide

  81. If we can “pause” a generator until someone
    outside calls next(), we can use yield to
    model waiting for an async function to call back
    #sjsJonathanL
    @jlipps

    View Slide

  82. monocle-js
    #sjsJonathanL
    @jlipps

    View Slide

  83. https://github.com/jlipps/monocle-js
    #sjsJonathanL
    @jlipps
    https://github.com/saucelabs/monocle

    View Slide

  84. #sjsJonathanL
    @jlipps

    View Slide

  85. #sjsJonathanL
    @jlipps

    View Slide

  86. #sjsJonathanL
    @jlipps

    View Slide

  87. In yield asyncFunction(), “asyncFunction” is
    not just a function: it is an “o-routine”. It can also
    be a Promise if you’re into that
    #sjsJonathanL
    @jlipps

    View Slide

  88. #sjsJonathanL
    @jlipps

    View Slide

  89. Yields in generators often mean “yield up”. When
    using them in Monocle, they mean “yield to”
    #sjsJonathanL
    @jlipps

    View Slide

  90. #sjsJonathanL
    @jlipps

    View Slide

  91. #sjsJonathanL
    @jlipps

    View Slide

  92. Error handling is the same as in regular sync
    JavaScript control ow: use try/catch
    #sjsJonathanL
    @jlipps

    View Slide

  93. #sjsJonathanL
    @jlipps

    View Slide

  94. Control ow is back in sync style! We can now
    use the built in control statements.
    #sjsJonathanL
    @jlipps

    View Slide

  95. #sjsJonathanL
    @jlipps

    View Slide

  96. Monocle-js lets you write async, non-blocking
    code using the built-in language features that
    are the most easy to reason about
    #sjsJonathanL
    @jlipps

    View Slide

  97. Generators are not my religion
    #sjsJonathanL
    @jlipps

    View Slide

  98. #sjsJonathanL
    @jlipps
    @nexxylove:
    “@jlipps is right about a lot of things, which
    means that it’s probably OK if he’s wrong about
    this one thing. I don’t want to generate any
    controversy here; I’m sure we can iterate on the
    idea and make it work for everyone!”

    View Slide

  99. There are lots of ways to write good JS code.
    Monocle-js has advantages and disadvantages,
    like every other approach
    #sjsJonathanL
    @jlipps

    View Slide

  100. If you write code with lots of serial async
    functions, Monocle-js is worth a look.
    #sjsJonathanL
    @jlipps
    https://github.com/jlipps/monocle-js

    View Slide

  101. Either way, educate yourself on good habits for
    async control ow in all approaches
    #sjsJonathanL
    @jlipps
    https://github.com/jlipps/async-showcase

    View Slide

  102. Thanks! Questions?
    To the discussion track...
    #sjsJonathanL
    @jlipps
    @jlipps
    @saucelabs
    http://saucelabs.com/careers

    View Slide