Table of Contents
Creating CollectionsJafar demonstrates how to use the functions he introduced in the previous section to create useful collections from a data source. He then applies the same code to a mouse-drag scenario to illustrate that events can be handled in the same manner.
Iterators and ObserversEvents and Arrays are both collections, just with different interfaces. Arrays use an iterator pattern. Events use an observer pattern. Jafar explains why he believes these two patterns are similar and why Events and Arrays should be handled in the same way.
Observable MetaphorWhile addressing an audience question, Jafar provides a real-world metaphor to further explain the difference between observers and iterators. He also walks through the implementation of the Observable.fromEvent() method.
Observables in ActionJafar demonstrates how Observables would work with the functions he introduced earlier. He runs examples using map(), filter(), and concatAll() and talks about the results.
Race Conditions and Nested ObservablesUsing observables can help eliminate race conditions since they sequence the incoming streams. They also are able to handle scenarios with nested observables (observables of observables). Jafar revisits his cake-cutting scenario to further explain nested observables.
TakeUntilThe takeUntil method copies all the data from a source observable into a new observable. However it completes once it reaches a “stop observable” which is passed as a parameter. This allows a seemingly infinite stream of data become finite.
Implementing Mouse MoveNow that Jafar has covered the concatAll() and takeUntil() methods, he revisits the mouse-move code. This demonstrates how user interface events can be reduced to simple collections and handled in a similar way to arrays.
MergeAll & SwitchLatestThe mergeAll() method functions similarly to the concatAll() method except that mergeAll will combine subsequent observables without waiting for a previous one to complete. Jafar explains why mergeAll can be useful and also covers the final flattening patter, switchLatest().
Netflix Search BoxJafar combines all the techniques he’s discussed up to this point to illustrate how to build the Netflix auto-suggest search box. The box will throttle key presses to limit network request and concatenate the received data until a new observable comes along.
Optimizing the SearchJafar spends a couple minutes talking about an optimized version of the search box code. He also explains the purpose of the retry method. Jafar also answers a number of audience questions about the different methods in this example.
Three-Dimensional CollectionsUsing the Netflix player example from earlier in the course, Jafar walks through the code that takes the tangled callback version of the player and converts it into a clean, three-dimensional collection.
Creating Array Functions
Exercises 1-5Jafar introduces the exercises and guides the class through the first five which lead up to implementing a map function. Each exercise is written and run in the browser. If an exercise is completed correctly, it will reveal the next exercise.
Exercises 6-11The next set of exercises involve filtering and flattening. Jafar demonstrates how to implement the filter and concatAll functions which can be used in more complex chaining. This leads to exercise 11 which requires the use of both map and concatAll.
Exercise 12In exercise 12, you will retrieve the id, title, and box art URL for every video in the collection. Before beginning the exercise, Jafar gives a few instructions to ensure only asynchronous-compatible code will be used.
Exercises 13-14In exercise 13, you will create a concatMap function that can be used to simplify consecutive concat/map calls. Exercise 14 puts this new function to use.
Exercises 15-17In these exercises, you will begin working with a reduce function. The reduce function performs operations on array items at the same time as opposed to one item at a time.
Exercises 18-19Exercise 18 involves using both the reduce and map functions to reduce multiple boxart objects to a single value. Exercise 19 demonstrates how to have the reduce function return a different type than the accumulator. Jafar also talks briefly about prototypical inheritance.
Exercise 20Exercise 20 combines many of the functions implemented in earlier exercises including reduce, filter, and concatMap.
Exercises 21-23When information is organized based on its position in an array, a zipping operation may be required to combine elements from equal positions in each array. Exercise 21 explains the need for zipping, exercise 22 implements a custom zip function, and exercise 23 puts this new function to work.
Exercise 24In exercise 24, you will retrieve each video’s id, title, middle interesting moment time, and smallest box art. This will require using most of the function created throughout all the exercises.
Debugging AsyncJafar spends a few minutes talking about debugging. When working with asynchronous code, step-into and step-over statements are not always as effective. Jafar suggests using the debugger directive and setting breakpoints.
Exercise 25Exercise 25 puts all five of the operators created in earlier exercises to use. The task is to convert Array data into tree structures that possess parent-child relationships.
Exercise 26aJafar begins the lengthy 26th exercise by setting up the multiple levels of mapping required. He also gives a few tips about logging progress before running any concatenation. This makes it easier to verify all the desired data has been pulled into the collection correctly.
Exercise 26bJafar finishes exercise 26 by zipping the some of the nested datasets to form the final collection.
Exercise 27Exercise 27 marks the first exercise where live, asynchronous data is queried. The stock ticker will continuously log the data as new packets arrive.
Handling Events with Observables
Exercises 28-30These exercises demonstrate how to transition from using explicit DOM events to Observables. Jafar also introduces the take function which will automatically dispose the subscription to the Observable after it has completed.
Exercise 31Exercise 31 introduces the takeUntil function which will continue to pull data from a stream until a stop observable is encountered. Similarly to the take function, takeUntil will also dispose once the stopping point is reached.
Observables and EventsBefore starting exercise 32, Jafar spends some time explaining how to respond to UI events wrapped in Observables. Execution code is placed inside a forEach so it can be run each time a new event is added to the collection.
Anatomy of an ObservableJafar reviews the anatomy of an Observable. An Observable is nothing more than an object with a forEach function. The observer referenced when creating the Observable will have onNext, onError, and onCompleted functions.
Observables vs. PromisesJafar describes the differences between Observables and Promises. He also spends a few minutes talking about how Observables compare to Node streams and what Observables may look like in ES7.
Exercise 32In this exercise, you will create a mouse drag event using Observables. To do this, you will retrieve only the mouse down events that occur before the next mouse up event.
Exercise 33Jafar points out the mouse drag code in the previous exercise has a couple issues. The mouse snaps to the upper left corner of the object whenever it is grabbed. Jafar uses the offsetX and offsetY properties to fix this issue.
Handling HTTP Requests with Observables
Exercise 34Most HTTP requests are exposed through a callback API. This exercise demonstrates how to use the getJSON method in jQuery to load remote data and handle success/error events. Jafar also begins building a larger example that will wrap the getJSON method in an Observable. First, he needs to get input from the user.
Searching WikipediaJafar uses JSONP to perform a search using the Wikipedia API because it will bypass any cross-origin issues. While his search function is still using callbacks, it demonstrates the API is working and allows him to them move it from a callback to an Observable.
JSONP as an ObservableNow that Jafar has a working JSONP call, he converts it into an Observable. This creates the forEach and dispose functions required for subscribing to the Observable. When JSON data is received, the Observable calls the onNext and onCompleted.
Composing a StreamAs the forEach function is called on the JSONP Observable, Jafar breaks down what the incoming data is going to look like to better explain which functions will be necessary to compose the stream.
Displaying Autocomplete DataJafar uses the map and switchLatest functions to compose the search results into a dataset that will populate the autocomplete box. The switchLatest function is the key for optimizing the behavior since it will dispose any of the previous requests.
distinctUntilChanged()To further optimize the search suggestions, Jafar what only changed values to be sent to the server. While there are a number of ways to implement this, he chooses to introduce the RX.distinctUntilChanged function which will only update the stream when a change has occurred.
Catching ErrorsJafar demonstrates how to handle errors that may occur when making network requests. The error handler is passed as the second parameter to the forEach and the retry function can be used to designate the number of attempts the Observable should make. This error handler will get called if after the desired number of attempts has been reached.
Handling Empty SearchesAfter answering a few audience questions, Jafar further optimizes the code by only performing searches when the search text is not empty. He uses the filter function to check for values
Showing the Search BoxJafar modifies the user interface so the search box is hidden by default and will be shown when the user clicks a Search button. This will allow him to demonstrate how to make the search subscription dependent on the search button being clicked.
Close Button ObservableAfter adding a close button to the search form, Jafar wants the click event from that button to dispose the current search stream and hide the form. To do this, he creates an observable from the click event and uses it in a takeUntil function.
Completing the Close ButtonJafar adds the correct functionality to the close button so it will hide the form, thus disposing the current stream of server request. He also talks for a few minutes about how to introduce side effects during the forEach cycle with the doAction function.
Audience QuestionsBefore moving on, Jafar spends takes some time to answer audience questions about the behavior of the form and some other general questions about Observables.
Creating an Observable ClassUp to this point, Jafar has been using the Observable class from the RX library. To better explain how Observables work under the hood, he creates an Observable class from scratch and implements the forEach and fromEvent functions.
Observable Map FunctionJafar revisits the implementation for the map function. Only this time, instead of adding it to the Array class, he implements it on the Observable class. Since it is on the Observable class, map will call onNext and pass the appropriate projection function.
Observable Filter FunctionThe Observable filter function has a similar implementation to the map function. Jafar leads the group through adding this function and explains the public forEach function with a little more detail.
Using the Observable ClassNow that Jafar has created his own Observable class with a map and filter function, he builds a simple program to see it in action. When a button is clicked, he transforms the mouse position value with the map function and returns a filtered result.
Observable Take FunctionThe Object.observe API will be landing in ES7. While it does allow developers to monitor for changes in variables, the API has its pitfalls. Jafar demonstrates how this API can be recreated as an Observable by implementing the take function. -
Implementing a Better Object.observeWith the take function implemented, Jafar uses it to convert the Object.observe function into an Observable. This allows him to fix some of the pitfalls in the API.
Binding Between Views and ModelsJafar puts his new Observable based on the Object.observe API to work by creating a two-way binding between the model data and the view. If the view is updated, the changes propagate to the model. If the model is updated, the changes are reflected in the view.
Syncing Data with the ServerWhile two-way binding in the application is nice, the changes reflected in the model and view should also be synchronized with the database. Jafar expands his example to include a database request as the model data is changed.
Observables as AnimationsJafar wraps up the course talking about how Observables can be used to sequence animations in a user interface. He also revisits the concept of syncing data with a database.