Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course
The "Observables vs. Promises" Lesson is part of the full, Asynchronous Programming in JavaScript (with Rx.js Observables) course featured in this preview video. Here's what you'd learn in this lesson:
Jafar 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.
Transcript from the "Observables vs. Promises" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Jafar Husain: Did I see a question back there?
>> Speaker 2: Yeah. So to reiterate the differences promise and observable. A promise is something that only happens once right, and then that promise also cannot be canceled, and an observable is basically a stream that can go on continuously.
>> Jafar Husain: Yes.
>> Speaker 2: So those are the main.
[00:00:31]
>> Jafar Husain: Yeah, and then one more which is, the observable is lazy, and let's go back to this example, right, if I create an observable, All I've done is I've created an object with a forEach method. That's all, I did, I haven't done a thing, right. So, if you call a function, which returns you an observable, you have every reason to believe that nothing is actually happened yet.
[00:00:51]
Not a thing. Whereas, if you call a function, and returns you a promise, something is already happening. A promise is eager, and an observable is lazy. And so by the time you have a promise, it's issued the xml http request already, or it's hooked up to the event already.
[00:01:05]
It's already done that. And, why is that not necessarily a good thing, in certain circumstances? Well, let's go back to the retry example. You can't retry a promise. There's no way to retry it. It's already happening, and it will never happen again. And so the only way to retry that promise, is to go find the original API, that created the promise and then call it again, but the problem is, when you make programs, and you distribute types, like a promise, you might pass that promise to fifteen other functions.
[00:01:31]
And then down here at function fifteen. It doesn't know about the API that was used to create the promise, right. All it knows is, I have a promise. But I wanna retry this thing because it erred. It's too late. That's the advantage of passing around an observable, it's a richer type, it can do more.
[00:01:45]
I can adapt an observable into a promise, lickety split, no problem. Just do a take one right. And then there's others APIs to adapt them into promises, it's very easy because an observable can do more than a promise. So it's very easy to turn an observable into a promise, you can't go the other way.
[00:01:59]
And so it behooves you to structure your program around richer types that have the semantics, that even trivial you guys need, like cancellation and retrying, and then if you happen to come across some API somewhere that wants to take a promise, instead of an observable, well it's easy to convert from an observable to a promise.
[00:02:14]
You see what I'm saying? It's safer to start with a richer type, and then if need be. You're working with a library that happens use promises. Convert it into a promise, because you can't go the other way. You've lost something. When you can't go from a promise to an observable, you can't go from something that's already happening to something that lazy.
[00:02:31]
It's already happening. It's too late. Does that make sense? So that's, those are the key differences between promises. You can't cancel them. They're one and done, they only give you one value and they finish. Right. So today. If you're using a promise to do a network request and then tomorrow it becomes a web socket, well guess what, in other words it sends you multiple values.
[00:02:48]
You gotta go through all your program wherever you're out promises and change them to accept observables, why don't you use observables in the first place? An observable that finished once is fine. There's nothing wrong with an observable one.. We're gonna be using mull all over the place. It's fine Usually for network requests.
[00:03:03]
Is that a good clarification of promises? So now we know what observable is, just an object with a forEach function waiting to be called. And when that forEach function is called, it's actually gonna do whatever work it has to do to schedule you getting pushed data and return a subscription such that when that's called, it's gonna do the work to make sure to cancel whatever operation under the hood is what would have triggered you getting data in the future.
[00:03:25]
Yeah question?
>> Speaker 3: This questions is always our observables the heart of reactive?
>> Jafar Husain: Yes, observable is the type is one type to rule them all for asynchronous programming. You can use observable for nearly every asynchronous API, there are some exceptions, but for the most part the types of API that you use in user interfaces, observables are appropriate for every single one of those asynchronous APIs you're likely to come across.
[00:03:49]
So the first step is, take whatever weird callback API you have, take the time to adapt it into observable. And then, when your API just looks like observables, all of a sudden you have this power to be able to just squeeze them together with the functions that you've learned yesterday, right?
[00:04:03]
But as soon as they get an observable and 15 callback APIs, you gotta resort to using weird callback and state machines, and then everything gets much more complicated. The first thing we did at Netflix, even before people fully understood observables, is we went through and we started to take the APIs that were callback based, and we adapted them into observables.
[00:04:21]
And you know what? The thing about an observable is, as we've seen earlier, you can use it just like an event, right. I mean it's not that different if you go forEach and then subscription dot dispose, instead of addEventListener or removeEventListener. So, and that's actually my recommendation to people which is that they start emitting observables and just teach people how to consume them the old way which is just like an event.
[00:04:38]
Okay, well you can call forEach and then you can call subscription dot dispose. That's not a lot more complicated, it's they're not getting the full benefit of observables because the full benefit of observables is using. Map filter takeUntil to glue it all together declaratively, but they can just start coding the same way they would've coded against events.
[00:04:53]
But over time, as you give your developers time to learn how to code more powerfully and code more compositionally, then when they're ready. There's all these APIs just waiting to be glued together with a few lines of code, and so that's a very good way to ease your system into something that can be used in this compositional reactive style.
[00:05:09]
Yes question.
>> Speaker 3: Do you have an example of any of those exceptions?
>> Jafar Husain: The best exception I can come up with at the moment, is not on the UI and it's in node stream. So who's familiar with node streams? Now the interesting thing about what's different about an observable and a node stream, is that we've talked about push and pull data sources right?
[00:05:29]
Where I just push information, or in the observation, is the producer is in control, and decides when information is pushed to the consumer. Iteration, the consumer's in control and the consumer requests, it decides when it gets the next out, because it requests it from the producer. A stream is a little like both.
[00:05:49]
So, although the producer is in control and is pushing values to the consumer, the consumer can say something which is not, don't give me any more values ever again. The consumer has this notion of saying. Pause, right. That's different. It's like a VCR hitting stop, versus pause. Subscription dot disposes stop.
[00:06:09]
VCR shuts down, who knows where you're, you're not even sure where your play position is, right. But pause, just says okay hold it, I'm cutting up cake, I'm distributing the cake but just cool it man. Stop throwing cakes at me, right, but then later on you can press play and then the producer just starts again, right.
[00:06:24]
That's not how an observable is, an observable doesn't let you hit pause, it will just keep throwing stuff at you, it doesn't care if you're ready. The only thing you can say to it is, never call me ever again, right. Node stream is this motion of push and pull where you can send values, but then the consumer can say whoa cool, but just for a little while and then later on can say start where you left off.
[00:06:44]
In general that's very useful for asynchronous IO, but frankly it doesn't really come up on the front end. On the front end, almost all of the data sources that you're gonna be working with set Timeout, set interval, events, XHR's, web sockets, they're all just push only. You can't pause them.
[00:07:00]
So observable, that's why I don't bother to teach streams in a front end class, because there are no node streams on front end. Not yet, maybe there will be at some point. But for things like file system, APIs in the browser, but that's not currently the case. So, my advice is don't worry about them so much.
[00:07:16]
Observable is definitely the best bet if you're doing front end APIs. Question in the back?
>> Speaker 3: Is there an equivalent to ES7's away async that promises adverse observables?
>> Jafar Husain: Not yet, so currently, what he's referring to is that there's an API in ES7, where you can declaratively write code that looks like it blocks but actually waits.
[00:07:38]
And so, what that's gonna look like in the next version of JavaScript, very possibly, so if you're working with promises, this is gonna be result, await, somePromise. Trying to make this a little more concrete.
>> Jafar Husain: So let's say you want to write a function that returns the price of a stock.
[00:08:19]
And accepts the name, the English language name of that stock. So, and then the first thing it does is, it gets the symbol for that stock. So Microsoft turns an MSFT, and then you can go to another API, which takes the symbol
>> Jafar Husain: and gets the price.
>> Jafar Husain: Using this magic await keyword on promises in JavaScript 7, allows you to write this code even though it's non-blocking in asynchronous, it actually looks like it's synchronous, that's pretty cool right.
[00:09:00]
What a great way to write async programming. Well the first thing I wanna call your attention to, is this is only good for a very narrow form of async programming, where there is really no concurrency going on. In other words, I want to do something asynchronous, and when that one thing that's asynchronous completes, I want to do something else that asynchronous and when that completes, I want to do something else that's asynchronous and that is great, when it happens and it will happen.
[00:09:22]
I think more often on the server than it will on the client. Because on the client very often. You're not dealing with this do this and then do that and then do that. You're dealing with concurrency. Meaning, you've got multiple things going at the same time, all the time when you're on the client.
[00:09:37]
Let's go back to that stock price example, right. I click a button and then I issue a network request, but then if somebody clicks another button, well I'm gonna issue another network request, and they're all gonna happen concurrently, unless I do something about it. That's really more the state of being of what you do with UI's because almost everything is triggered with an event.
[00:09:53]
And then may lead to another asynchronous action. And so you're dealing with concurrency and I can't do that with this. Right, I cannot model that example of, I click a button, I issue a request to a stock but then if somebody clicks another button, I cancel that request and then start another one.
[00:10:07]
That requires us thinking about two items happening at the same time, and this, as nice and as pretty as it seems, and it's a very nice syntax, does not help you solve the hardest problems that you have on user interfaces, which is concurrency. It is a very nice syntax for that narrow case of you've got to do one thing, and then another thing, and then another thing.
[00:10:23]
Frankly I'd think it'll be much more useful on the server, than it will on the client, because in the client, your doing so much with events which means concurrency, right you're listening for an event and then every time that event happens. You might do something else but then while that thing is going on, another event might happen and then you do that as well, so that whenever you're doing two things at the same time, this syntax isn't generally very useful.
[00:10:44]
Now the question was, will this syntax work for observable and that is a very good question and that's currently actually a proposal that we have for JavaScript 7. We're actually working to make sure that it is possible, in those narrow cases, to be able to use the await and async syntax for observables as well.
[00:11:01]
So let's say you had several observables of one, you could use, hopefully, if the proposal passes, you could use the same async awaits syntax. For observables of one.
>> Speaker 4: So probably you will just do forEach and then you'll do it like on the next lessons [COUGH]
>> Jafar Husain: Yes although technically you could also use the JavaScript 6, so this is actually just syntactic sugar for something like this in JavaScript 6 where you could write almost exactly the same code
[00:11:31]
>> Jafar Husain: It looks slightly different, but it's basically the same idea.
>> Jafar Husain: This is what you're gonna actually do in JavaScript 6. Using a helper function, using this little async. So now it's not a keyword, it's a function. Using a little helper function you could actually take what I don't have time to explain all of these all of this but all of what's going on here.
[00:11:53]
I can just point out to you that it's pretty much the same amount of code. So this right here is an example below, which will work in JavaScript 6, and you can make work on both observables and promises, up top there is a syntax that will work in JavaScript 7 and it's open.
[00:12:06]
It's an open question about whether it'll work with promises or observables. I highly recommend you don't use observables just to keep the syntax above there, because that is a very narrow case of concurrency when you're dealing on the client. So it's not gonna solve most of your problems, and furthermore if you take on promises, you have just lost a lot of expressiveness which will be very very useful to you in modern single page web applications.
[00:12:30]
So I think async away is not as big a deal as people may think it is, because A, there's already a feature in ES6 which allows you to write code almost exactly the same way that the example at the top I think is a little clearer. Cuz you got the away keyword which I think is a little clearer to people.
[00:12:42]
But it's actually not that much more there in terms of syntactic expressiveness. Any other questions? So let's get back to observable. Now that we kinda got an idea of how an observable works, it's an object with a single for each method. Right? We're using functions to just build a bigger and bigger object with a single forEach method, and then finally run it by calling forEach.
[00:13:05]
Let's take a look at some examples of stuff in action here so.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops