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.

174ae1c2a863b7daf240a86da84671bd?s=128

Jonathan Lipps

May 10, 2014
Tweet

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
  2. #sjsJonathanL Jonathan Lipps • Director of Ecosystem & Integrations •

    Sauce Labs @jlipps • @saucelabs Ecosystem & Integrations
  3. “Asynchronous Control Flow” #sjsJonathanL @jlipps

  4. Sync #sjsJonathanL @jlipps Async

  5. Sync #sjsJonathanL @jlipps Async Blocking

  6. Sync #sjsJonathanL @jlipps Async Blocking Immediate execution

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

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

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

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

    by assignment Errors handled with try/catch Deferred execution
  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
  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
  13. Sync Async #sjsJonathanL @jlipps

  14. Sync Async #sjsJonathanL @jlipps

  15. Sync Async #sjsJonathanL @jlipps

  16. Control Flow is how you structure logical dependencies between statements

    in your programs #sjsJonathanL @jlipps
  17. Control Statements are familiar bits of JavaScript, usually learned easily

    and early on #sjsJonathanL @jlipps
  18. #sjsJonathanL @jlipps

  19. if #sjsJonathanL @jlipps

  20. if then #sjsJonathanL @jlipps

  21. if then for #sjsJonathanL @jlipps

  22. if then for while #sjsJonathanL @jlipps

  23. if then for while do #sjsJonathanL @jlipps

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

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

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

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

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

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

    return #sjsJonathanL @jlipps
  30. #sjsJonathanL @jlipps

  31. #sjsJonathanL @jlipps

  32. #sjsJonathanL @jlipps

  33. #sjsJonathanL @jlipps

  34. #sjsJonathanL @jlipps

  35. #sjsJonathanL @jlipps

  36. x = 1 #sjsJonathanL @jlipps

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

  38. x = 1 y = x + 2 y <

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

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

    x y++ y-- x++ #sjsJonathanL @jlipps
  41. Sync control ow is easy #sjsJonathanL @jlipps

  42. Async control ow can be tricky when there are dependencies

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

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

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

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

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

  48. The trouble with callbacks #sjsJonathanL @jlipps

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

  50. #sjsJonathanL @jlipps

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

    @jlipps
  52. #sjsJonathanL @jlipps

  53. #sjsJonathanL @jlipps

  54. :-( #sjsJonathanL @jlipps

  55. 1. Visual unreadability / “Pyramid effect” 2. Error handling 3.

    Control ow: conditionals #sjsJonathanL @jlipps
  56. #sjsJonathanL @jlipps

  57. #sjsJonathanL @jlipps

  58. Obscuring functionality #sjsJonathanL @jlipps

  59. Need to remember to return #sjsJonathanL @jlipps

  60. 1. Visual unreadability / “Pyramid effect” 2. Error handling 3.

    Control ow: conditionals 4. Control ow: loops #sjsJonathanL @jlipps
  61. #sjsJonathanL @jlipps

  62. #sjsJonathanL @jlipps

  63. Checking conditions #sjsJonathanL @jlipps

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

  65. Async control ow with callbacks involves lots of boilerplate. We

    can haz framework? #sjsJonathanL @jlipps
  66. https://github.com/caolan/async #sjsJonathanL @jlipps

  67. async.series #sjsJonathanL @jlipps

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

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

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

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

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

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

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

    @jlipps
  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
  76. What do generators have to do with any of this?

    #sjsJonathanL @jlipps
  77. Generators are a new ES6 feature available in node 11

    and up, by passing the --harmony ag to node #sjsJonathanL @jlipps
  78. Generators allow lazy construction of potentially in nite sequences #sjsJonathanL

    @jlipps
  79. Code in generators can also respond to behavior in the

    outside world! They do this with the new yield keyword. #sjsJonathanL @jlipps
  80. #sjsJonathanL @jlipps

  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
  82. monocle-js #sjsJonathanL @jlipps

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

  84. #sjsJonathanL @jlipps

  85. #sjsJonathanL @jlipps

  86. #sjsJonathanL @jlipps

  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
  88. #sjsJonathanL @jlipps

  89. Yields in generators often mean “yield up”. When using them

    in Monocle, they mean “yield to” #sjsJonathanL @jlipps
  90. #sjsJonathanL @jlipps

  91. #sjsJonathanL @jlipps

  92. Error handling is the same as in regular sync JavaScript

    control ow: use try/catch #sjsJonathanL @jlipps
  93. #sjsJonathanL @jlipps

  94. Control ow is back in sync style! We can now

    use the built in control statements. #sjsJonathanL @jlipps
  95. #sjsJonathanL @jlipps

  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
  97. Generators are not my religion #sjsJonathanL @jlipps

  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!”
  99. There are lots of ways to write good JS code.

    Monocle-js has advantages and disadvantages, like every other approach #sjsJonathanL @jlipps
  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
  101. Either way, educate yourself on good habits for async control

    ow in all approaches #sjsJonathanL @jlipps https://github.com/jlipps/async-showcase
  102. Thanks! Questions? To the discussion track... #sjsJonathanL @jlipps @jlipps @saucelabs

    http://saucelabs.com/careers