
Rethinking Asynchronous JavaScript
Learning Paths:
Topics:
Table of Contents
Parallel vs. Async
Course Introduction
Kyle Simpson (@getify) begins his course on Async Patterns with a brief introduction of himself and an overview of the course agenda. He runs a few open source projects like LabJS, Grips, and Asynquence. He is also the head of curriculum for the developer/engineer training school Maker Square.Single Threaded JavaScript
In the context of programming, Parallelism is the utilization of multiple threads in an operating system. Routines are able to run at the same time regardless of execution order. JavaScript, however, is single threaded and only one line of code can be executed at any given time. Kyle explains these concepts to build a basis for understanding asynchronous programming.Concurrency
Kyle introduces concurrency as two higher-level tasks happening within the same timeframe. He illustrates these higher-level tasks or macro-tasks might be composed of many micro-tasks. As each micro-task is initiated, it queues up behind any other existing tasks and is executed in order.
Callback
Callback Hell
Kyle describes callbacks as a continuation of code. One part of the program executes, then later, another part of the program continues. He also introduces “callback hell” and makes the argument that the classic sideways pyramid shape has nothing to do with the inherent problems created by callbacks.Exercise 1
The code in exercise 1 will be reimplemented throughout the next seven exercises. Each time you will be using a different async pattern. In this exercise, you will write async flow-control code while only using callbacks.Exercise 1 Solution
Kyle walks through the solution to exercise 1.Callback Problems: Inversion of Control
In the context of callbacks, inversion of control is the notion of having code under your control in one part of the program, then handing control over to a callback in another part of the program. Kyle explains why inversion of control is one of two major problems with callbacks and shares a few problem scenarios.Callback Problems: Not Reason-able
The second problem with callbacks is they don’t handle divergent code very well. Kyle describes this as not being reasonable or understandable. His goal is to write async code that looks synchronous and sequential. This can’t be done with callbacks alone.Non Fixes
Kyle spends a few minutes showing a number of “non fixes” for callbacks. These are techniques that have been developed to make callbacks more reliable, however they tend to introduce their own side effects.
Thunks
Synchronous and Asynchronous Thunks
Thunks are functions that already have everything they need to return a value. They do not require any parameters. Kyle explains how thunks typically manifest themselves as a function wrapper around some state or token value. Hey also demonstrates the difference between synchronous and asynchronous thunks.Exercise 2
In this exercise, you will write the same async flow-control code using thunks instead of callbacks.Exercise 2 Solution
Kyle walks through the solution to exercise 2.Thunks and Closure
After completing exercise 2, Kyle spends a few minutes diving deeper into the relationship between thunks and closure. Thunks use closure to maintain state and eliminate the factor of time in asynchronous code.
Promises
Native Promises
Promises represent a placeholder for a future value. They solve the inversion of control issue that exists with callbacks by providing completion events for asynchronous tasks. This puts the control back inside the application.Promise API
Using the checkout example, Kyle introduces the native Promise API. He also explains that even though promises appear to use callbacks, there is a increased level of trust. Promises will only resolve once, will have either a success or error outcome, and are immutable once resolved.Promise Flow Control
Promises manage sequential flow controls through chaining. Promises are chained together when one promise returns a subsequent promise in its success handler. Kyle shares a few of the previous code examples reimplemented with promise chaining.Exercise 3
In this exercise, you will use promises to implement the flow-control code for retrieving files.Exercise 3 Solution
Kyle walks through the solution to exercise 3.Exercise 3 Questions Part 1
Kyle spends some time answer audience questions about exercise 3.Exercise 3 Questions Part 2
Kyle continues answering audience questions about exercise 3 before moving on to the next exercise.Exercise 4
In this exercise, you will modify the promise-based flow control code so it can be used with any number of steps.Exercise 4 Solution
Kyle walks through the solution to exercise 4.Abstractions
Kyle introduces a few abstractions in the promise API. Promise.all() takes in an array of promises and will wait for all promises in the array to resolve. Promise.race() also receives an array of promises, however, it only waits for whichever promise in the array resolves or rejects first.Sequences & Gates
While native promises provide some API for chaining and sequencing, rewriting the logic each time can be redundant. This led Kyle to create the open source library Asynquence. His library adds a number of abstraction methods which make sequencing and gating promises easier.Exercise 5 & 6
In these exercises, you will use the Asynquence library to get the list of files. For exercise 5, the Asynquence will replace the code in exercise 3. Exercise 6 will apply Asynquence to the exercise 4 solution.Exercise 5 Solution
Kyle walks through the solution to exercise 5.Exercise 6 Solution
Kyle walks through the solution to exercise 6.
Generators
Generator Example
Generators are a new type of function in ES6. In asynchronous programming, generators solve the non-sequential, non-reasonable issues of callbacks. When a generator is called, it returns an iterator which will step through the generator, pausing anytime the yield keyword is encountered. After introducing the concept of a generator, Kyle shares a simple code example.Messaging
If the yield keyword in a generator is called with a value, that value will be returned to the iterator along with a “done” boolean value. This allows messages to be sent outside of the generator. Kyle explains why this is useful and also demonstrates that subsequent calls to the next() method can be used to pass message back into the generator.Messaging Questions
Kyle spends a few minutes reviewing the way generators send and receive messages. He also answers a number of audience questions about generators, iterators, and the use of the yield keyword.Async Generators
Kyle demonstrates how generators can be used in asynchronous applications. The yield keyword will block a generator while an async call is being executed. Values returned from the async call can be passed back to the generator allowing it to resume and sequentially trigger other async operations.Promises + Generators
While generators completely solve the issue of sequencing asynchronous operations, they are still susceptible to inversion of control. Since promises solve the inversion of control issue, Kyle explains how they should be combined with generators to create better asynchronous code.Exercise 7
In this exercise, you will now use generators to write the async flow control code from the previous exercises.Exercise 7 Solution
Kyle walks through the solution to exercise 7.Quiz
Kyle spends a few minutes quizzing the audience on the async patterns he’s covered up to this point.
Observables
Events + Promises
Promises work well with asynchronous events that occur once. A stream of events, however, make promises more difficult to use because a promise can only be resolved once. Kyle explains a few of the ways promises could work with event streams but stresses the need for and alternative solution.Observables
While observables do not currently exist in the JavaScript specification, third-party libraries have begun implementing them. After introducing the concepts behind observables, Kyle demonstrates how use the RxJS library from Microsoft. He shares code that wraps an observable around a button’s click event.Reactive Sequences
Reactive sequences are the implementation of observables that Kyle added into Asynquence. Kyle introduces the API for creating a reactive sequence and shares a few code examples. The power of a reactive sequence lies in the ability for it to be composed with other sequences.Exercise 8
In this exercise, you will create your own streams and stream responses.Exercise 8 Solution Part 1
Kyle walks through the solution to exercise 8.Exercise 8 Solution Part 2
Kyle continues the exercise 8 solution by answering a few audience questions.
CSP
Concurrency + Channels
CSP or, Communicating Sequential Processes, involves modeling concurrency through channels. These channels use blocking techniques to send and receive messages. After explaining some of the concepts behind CSP, Kyle shares a simple code example.Blocking Channels
Kyle further explores how blocking channels are implemented in CSP. In this case, the messaging occurs inside an infinite loop. The yield keyword will block the loop while waiting to put a message into the channel or take a message from the channel.Event Channels
Kyle spends a few minutes explains how CSP can be applied to DOM events. He also demonstrates how he uses CSP inside of the Asynquence library.Exercise 9
In this exercise, you will implement that same functionality as in exercise 8 while only using CSP.Exercise 9 Solution
Kyle walks through the solution to exercise 9.Recap
Kyle summarizes the various async patterns he covered through the course. This includes callbacks/thunks, promises, generators, observables and CSP. He also shows his “Tale of Three Lists” demonstration which highlights the differences in some of these patterns.Exercise 10
Kyle assigns exercise 10 as an extra credit exercise. It involves implementing the Tale of Three Lists example using either reactive sequences or CSP.Wrap-up
Kyle concludes his course on Async Patterns with a few final thoughts.