-
What's the difference between event and an array?
- They are both collections.
-
Iterator
- You have producer and consumer
-
Consumer requests information one at a time from producer until
- Producer says I have no information for you
- Producer says an error occurred
- var iterator = [1,2,3].iterator();
console.log(iterator.next());
{ value: 1, done: false }
...
{ done: true }
-
Observer Pattern
- document.addEventListener(
"mosemove",
function next(e) {
console.log(e);
});
-
Producer pushes data at you
- Producer decides when you get the data
- The observer pattern iterates you
- We need a way for producer to tell the consumer I don't have no more data for you
-
Iterable
- Example of array is iterable
- You can ask for an iterator from
- Array is not iterator, but you can ask for the iterator, because of that is iterable
-
Observable
- Opposite of iterable
- It's a collection that arrives over time
-
Can model
- Events
- Async Server Requests
- Animations
- They are the same, the only difference is who is in control
Pulling (iterable) vs Pushing (observable)
-
Intro
-
First we need to take all the weird APIs and adopt them as observables
- var mouseMoves = Observable.fromEvent(element, "moousemove");
- Subtopic 2
-
Subscribe
- var subscription = mouseMoves.forEach(console.log);
-
Unsubsribe
- subscription.dispose();
- This is cosumer saying I don't need/want/care about the data anymore
-
Error & Done
-
var subscrption = mouseMoves.forEach(
// next data
event => console.log(event),
// error
error => console.error(error),
// completed
() => console.log("done"));
- 2 new interfaces which were missing
- The same semantics we have for iterator
-
This also can be expressed by an object with onNext, onError, onCompleted properties
- moouseMoves.forEach({
onNext: event => console.log(event),
onError: ...
onCompleted: ...
-
Observer object
- {
onNext: ..
onError: ..
onCompleted: ..
}
-
Observable is always created using a forEach method
- forEach is how you get the data out
- Observable.fromEvent = function(dom, eventName) {
return {
forEach: function(observer) {
..
}
}
-
Flattening strategies
-
concatAll
- flattens observables of observables
- elements come out in order of the collection there are inside of arrives
-
Subtopic 3
- {} and {4} are waiting until {3} arrives and the collection is done
- thse observables don't start emitting values until you forEach over them
- this is a cold observable
- they are not going to do anything until you call forEach
- we buffer observables
-
this solves race conditions
- Im only interested in these events after these events occur (but they are fired asynchronously)
-
not good idea for infinite streams
- you will never get to the next stream
- but there is a way how we can stop listening to infinite streams (like drag and drop)
- and might get buffer overflow
- not use for use for traffic lines when some of the lines is closed
- DOM events are kinda infinite streams
-
takeUntil
- it takes a source observable and a stop observable and returns an observable
- evety time source observable emits something, it forwards that on
- as soon as the stop observable emits a single value (onNext, onCompleted) it completes the overall observable
- stop collection value is irrelevant
-
that's how we can take 2 infinite observables and combine them together to create one that ends
- Subtopic 1
- don't unsubscribe from events, create streams that complete when you want them to complete
-
mergeAll
- lines, first comes first serves
-
when 4 lines close into one
- Subtopic 1
- you don't care about the order vs CONCATALL when you care about the order
-
switchLatest
-
when a new observable arrives, it unsubsribes from the previous one
- Subtopic 1
-
only listens to one inner observable at a time
- usually because there is something newer we are interested in more then the previous one
- we have an observable of clicks, each click gets mapped out to a HTTP observable, so we get 2 dimensional observable
-
we are waiting for observable, not for data
- so empty observable will swtich
-
most common thing used in UI
- browser has a queue of outgoing requests, this approach can prevent outgoing request to go out before its issues (for example when you click a button multiple times)
- only works when you want to stop listening to inner observable based on the same condition it causes you to get a new inner observable
-
solving problems in 4 steps
- 1. What collections (event) do I have
- 2. What collection (event) do I want
- 3. How do I get from collections I have to the collection I want
- 4. What Im gonna do with the data that comes out of the collection I want
-
autocomplete box
- 1. keypress, network request
- 2. stream of search results
-
Subtopic 2
- the getJSON observable would look like "...........................data"
- collections can be one value (like arrays can contain one value), observables can have one value, getJSON is one value, ".........data" and then immediately onComplete()
-
throttle(250)
- ..abc...def.... => ...c...f
- drops items that come very close to each other and takes the last one
-
map
- map is alaways about substitution - replacing a stream with something else
- every key press is substituted by a observable that represents a network request
-
we have an observable of keypresses and each key press gets replaces with a new observable (so we have 2 dimensional observable)
- therefore we need to flatten it later
- when flattening, we need to solve the race condition problem
-
takeUntil(keyPresses)
- as soon as I type something on the keyboard and the network request hasn't been returned (....X..data), the observable completes and it becomes empty
-
can be simplified to this:
-
Subtopic 1
- throttle now is purely an performance optimization
-
retry
-
promises cannot be cancelled
- promises are mose useful on the server
- observable are lazy - it doesn't do anything until you call forach on it
- promises cannot be easily retried, promise can only send a single value and not a stream of data
-
retry takes an observable, calls forEach and if onError gets called, then it will increment the counter and retry again
- and if it still gets an error, it will forward it to whoever is listening
-
netflix player
-
Subtopic 1
- init() returns a simple observable with "true" value (it an observable of one)
- map takes this observable (doesn't care about the returned value - therefore ()=>) and listens to all playattempt events (click on play button)
- authorize just makes sure you are allowed to play the movie and comes back with a decryption key
- cancels is a stop button
-
catch - we dont want the stream to die when there is an error, in this case we just return an empty observable which will case like nothing happened when you clicked the play button - we can do better
- its only on the inner observable, on on the outers like init()
- we are assuming that if you click play multiple times, it always clicks cancel before (its play, cancel, play, cancel, ... sequence)
-
Other
-
concatMap
- receives a function that returns array and flattens this array
- instead of doing map().concatAll()
-
reduce
- takes array with many many items and reduces to an array with one item
- returns observable that completes with array of size one
-
it has two parameters
- reducer function
-
initial value (optional)
- if not used, initial value of acc would be the first element and curr would start from the second element
- used when we want to accumulate values into a new type, like map
- Like this example
- we should use whenever we are looking for something biggest or smallest
- one of 2 functions that has 2 arguments
-
zip
- like teeth in a zipper, one from each side of an array until one of the arrays stop
- zip(leftArray, rightArray, combinerFunction(left, right)));
- one of 2 functions that has 2 arguments
-
Tips & Tricks
-
Object.create()
- Every object in Javascript is linked (linked list) to an empty object
- If I call this on an object, I create a whole new object that is linked to object it was created from
- If I acccess an attribute which is empty, it automatically goes to the next linked object, which might be sometimes very cool when we want immutable object
-
cheap way of copying object!!!
- but someone can change the original object and that mocks the copy
-
Object.seal()
- No one can modify the object