01 - Course Introduction
Async Patterns
- Parallel vs Async
- Callbacks
- Thunks
- Promises
- Generators/Coroutines
- Event Reactive (observables)
- CSP (channel-oriented concurrency)
02 - Single Threaded JavaScript
Parallel vs Async
Threads
Single Thread
- Everything in JavaScript is happening on a single thread: your JS, your styles, your garbage collection, etc. This is why you get jitters in the UI. When your UI is trying to repaint at 60fps and something else requires computation, you get a momentary jitter.
- Things happen concurrently in JavaScript to avoid unnecessary stalls in computer/user interaction. It’d be weird if you made a synchronous Ajax call which made the page freeze up until the request was completely done. Instead, Ajax calls happen concurrently with other tasks (like your UI repainting), even though at any given instant only one of those tasks can be executing on the tread (i.e. event loop).
- 『Asynchronous programming』 in JavaScript is better patterns for concurrency management, i.e. patterns on top of the existing pattern we have for concurrency (callbacks) like generators and promises.
03 - Concurrency
04 - Callback Hell
callbacks
1 | setTimeout(function(){ |
callbacks == continuations
Callbacks are also called “continuations” because they are code continuations in the sense that you are executing code now and then later. That “later” could be any time, for example when a network call is finished. But the idea is that you want some code to run now and you want some code to run later. And when that 『later』 code runs, you essentially want to pick up where you left off from before. This is why callbacks are often called “continuations”.
callback hell
1 | setTimeout(function(){ |
Is callback hell indentation and nesting?
1 | function one(cb) { |
Callback hell has nothing to do with the indentation of your code, it’s deeper than syntax.
Callback hell has to do with an inversion of control, which means there’s a part of my code I’m responsible for executing (the “do it now” stuff) and there’s part of my code that I’m not in charge of executing (the “do it later” stuff, i.e. got a response from server? Now do something). So in other words, when I give somebody a callback I’m saying “here you go, now you are in control of when this thing executes”. You are trusting that the callback will be called:
- Not too early
- Not too late
- Not too many times
- Not too few times
- No lost context
- No swallowed errors
- …and more!
In other words, every callback you’ve ever written has an existing bug of trust (even if you haven’t been bitten by it yet)
05 - Exercise 1
Instructions
This exercise calls for you to write some async flow-control code. To start off with, you’ll use callbacks only.
Expected behavior:
- Request all 3 files at the same time (in “parallel”).
- Render them ASAP (don’t just blindly wait for all to finish loading)
- BUT, render them in proper (obvious) order: “file1”, “file2”, “file3”.
- After all 3 are done, output “Complete!”.
code setup
1 | function fakeAjax(url,cb) { |
06 - Exercise 1 Solution
1 | function fakeAjax(url, cb) { |
07 - Callback Problems - Inversion of Control
1 | // line 1 |
We are in control of line1
and line2
, line3
and line4
are not in control.
1 | trackCheckout( |
Trust
- not too early
- not too late
- not too many times
- not too few times
- no lost context
- no swallowed errors
08 - Callback Problems - Not Reason-able
WRITING ASYNCHRONOUS PROGRAMS IN A SEQUENTIAL MANNER
Example of how we think about code vs how it really works:
1 | console.log("First thing happens"); |
That code is essentially expressing in our brains something that works like this:
1 | console.log("First thing happens"); |
But to the javascript engine, this is what it’s doing:
1 | console.log("First thing happens"); |
09 - Non Fixes
10 - Synchronous and Asynchronous Thunks
Thunks
- Thunks are an interesting pattern to take time out the equation when trying to access a value.
- First time you set them up, they do they work, but they don’t give you the value until you pass in the callback.
- These are the conceptual underpinnings of a Promise.
- “Thunks are a very lightweight way of solving asynchronous sequencing issues without having to invoke some huge library.”
- “I don’t need a library. I just need to better understand how to use my currently available tools.”
- Thunks are about using closure to maintain state.
- If we can use this tool, a thunk, as a wrapper around a time-based value of state, we can then compose values together without having to worry about the ordering. Time becomes a non-issue.
1 | function add(x, y) { |
AsyncThunk
1 | function addAsync(x, y, cb) { |
Make Thunk (lazy thunk)
1 | function makeThunk(fn) { |
1 | function addAsync(x, y, cb) { |
What is temporary dependent
1 | function getData(d, cb) { |
11 - Exercise 2
Instructions
You’ll do the same thing as the previous exercise(s), but now you should use thunks.
Expected behavior:
- Request all 3 files at the same time (in “parallel”).
- Render them ASAP (don’t just blindly wait for all to finish loading)
- BUT, render them in proper (obvious) order: “file1”, “file2”, “file3”.
- After all 3 are done, output “Complete!”.
code setup
1 | function fakeAjax(url, cb) { |
12 - Exercise 2 Solution
Notice the active thunk
1 | function fakeAjax(url, cb) { |
13 - Thunks and Closure
14 - Native Promises
There is a promises hell, I promise you.
It’s important to understand the concepts behind promises and what they are before you learn the API. This is the reverse of the way things are typically taught. Remember that promises aren’t perfect. When you run into a gotcha, you need to understand the why. There is very much “promises hell”.
Promises allow you to reason about something on the promise of the thing before you have the actual thing itself. They are a codification of the idea that we need a placeholder to eliminate time as a concern wrapped around a value (a future value). They allow you to reason about and write code around a future value, all within the same space, whereas with callbacks you have to make jumps around “this happened here, now in this other file is what happens when you get the value” etc.
Promises are like event listeners. You call the thing and then listen for the outcome. Except in a promise, the listener action is the then()
action.
1 | // listener |
The fundamental design principles of promise are:
- they only resolved once
- they result in either a success OR an error
- messages are passed / kept
- exceptions become errors
- they are immutable once resolved (you can send it anywhere, even outside your system, and you know it won’t be changed from under you)
Promises
Future Values
“Completion Events”
15 - Promise API
Async Patterns: “completion event”
1 | function finish () { |
Async Patterns: (native) promise
1 | function trackCheckout(info) { |
1 | function finish () { |
Still callbacks?
Promise Trust
- only resolved once
- either success OR error
- messages passed/kept
- exceptions become errors
- immutable once resolved
16 - Promise Flow Control
Async Patterns: promise flow control
1 | doFirstThing |
Chaining Promises
1 | doFirstThing() |
1 | function delay(num) { |
1 | function getData(d) { |
17 - Exercise 3
Instructions
You’ll do the same thing as the previous exercise(s), but now you should use promises.
Expected behavior:
- Request all 3 files at the same time (in “parallel”).
- Render them ASAP (don’t just blindly wait for all to finish loading)
- BUT, render them in proper (obvious) order: “file1”, “file2”, “file3”.
- After all 3 are done, output “Complete!”.
code setup
1 | function fakeAjax(url, cb) { |
18 - Exercise 3 Solution
1 | function fakeAjax(url, cb) { |
21 - Exercise 4
code setup
1 | // ************************************** |
22 - Exercise 4 Solution
1 | // Request all files at once in |
23 - Abstractions
Async Patterns: promise “gate”
1 | Promise.all([ |
Async Patterns: promise timeout
1 | var p = trySomeAsyncThing() |
24 - Sequences and Gates
sequence = automatically chained promises
1 | ASQ() |
25 - Exercise 5 and 6
Solve Exercise 3 and 4 using ASQ
1 | // ************************************** |
1 | // ************************************** |
28 - Generator Example
Generators(yield)
Async Patterns: generators
1 | function* gen() { |
29 - Messaging
Async Patterns: generators
1 | function* main() { |
Async Patterns: generator coroutines
1 | function coroutine(g) { |
Async Patterns: generator messages
1 | var run = coroutine(function* () { |
31 - Async Generators
Async Patterns: yield tasks
1 | function getData(d) { |
32 - Promises and Generators
Async Patterns: generator + sequence tasks
1 | function getData(d) { |
33 - Exercise 7 ❓
Instructions
You’ll do the same thing as the previous exercise(s), but now you should use asynquence and a generator.
Expected behavior:
- Request all 3 files at the same time (in “parallel”).
- Render them ASAP (don’t just blindly wait for all to finish loading)
- BUT, render them in proper (obvious) order: “file1”, “file2”, “file3”.
- After all 3 are done, output “Complete!”.
code setup
1 | function fakeAjax(url,cb) { |
34 - Exercise 7 Solution
1 | // ************************************** |
35 - Quiz
1. What is “callback hell”? Why do callbacks suffer from “inversion of control” and “unreasonability”?
- inversion of control
- none-local none-sequencial
2. What is a Promise? How does it solve inversion of control issues?
- future value
- callback manager
3. How do you pause a generator? How do you resume it?
- yield
- next
4. How do we combine generators and promise for flow control?
- yielding a promise
related
36 - Events and Promises
Concurrency: Event (+ Promise)?
Async Patterns: events + promises
1 | var p1 = new Promise(function(resolve, reject) { |
problem: promise will only be resolved once.
1 | $('#btn').click(function(evt) { |
problem: there is nonsense to use promise.
Async Patterns: events + lists
1 | $('#btn').click(function(evt) { |
37 - Observables
Async Patterns: RxJS observables
1 | var obsv = Rx.observable.fromEvent(btn, "click"); |
38 - Reactive Sequences
Async Patterns: reactive sequences
1 | function fromEvent(el, eventType) { |
1 | var rsq1 = fromEvent(btn, 'click'), |
39 - Exercise 8
Instructions
In this exercise, we’re going to practice with “reactive sequences” programming (aka “observables”) using asynquence.
Set up a reactive sequence for the stream of click events from the button. Hint:
ASQ.react.of()
andrsq.push(..)
Set up another reactive sequence that samples the sequence stream from (2) once per second. In other words, if you click the button multiple times in a second, you only get one event message. Hint:
setInterval(..)
The sampled sequence should add a “clicked!” message to the list.
code setup
1 | $(document).ready(function () { |
40 - Exercise 8 Solution Part 1
1 | $(document).ready(function () { |
42 - Concurrency and Channels
CSP: Communicating Sequential Processes
Async Patterns: channel CSP
1 | var ch = chan() |
43 - Blocking Channels
Async Patterns: channel CSP
1 | csp.go(function* () { |
1 | csp.go(function* () { |