 We're going to talk about concurrency. We're going to talk about async and await as a sort of modern approach to doing concurrency in JavaScript. And I'm Simon, so I'm a JavaScript and React engineer. I've been doing JavaScript for a long time and React for a number of years now. I have a team just outside of Jakarta. CodeFox is our company. And so you can also find me on Twitter with sstur underscore. So today we're going to talk about concurrency. And it's kind of a technical topic. So I'll try to explain it as simply as I can. But you're definitely going to see some code. So we're going to go through some code and talk about some concepts. Maybe we should start with, is everybody a JavaScript programmer or does write JavaScript in here? OK, cool, just checking. And so what about using more modern ES6 constructs? Is everybody using ES6 at least has some familiarity with that? Yeah? OK, cool, because that's what the code slides that we're going to look at is all ES6. So let's talk about what is concurrency? So concurrency is doing multiple tasks in a period of time. So typically, one core can only do one thing at once, as well as other pieces of hardware can only do a single thing at a time. But over a stretch of time, we want to do multiple things. So a web server wants to serve multiple requests for a web page. A script wants to read multiple values from a database before it returns the request. And so what we're really talking about is doing multiple tasks over a period of time. And some of those things we can do in parallel, and some things we have to do one at a time. And so generally, order-dependent or partially ordered units or sorry, order-independent or partially ordered units of work is where concurrency happens. So this is just an example of multiple tasks that may start at various different times, but are kind of running over the same period of time. So they're running in parallel, essentially. Some of these are, right? And so this is something that is pretty hard to do in computing, right? In particular, it's hard to reason about, it's hard to, it leads to race conditions, it leads to difficult models of things changing over time, right? And so concurrency is specifically important when we're dealing with user input, sorry, input output is in like network requests, also user input, users interacting with the system and reading, writing from disks. Anything that is kind of considered asynchronous type of activity, right? Something where the CPU needs to stop and wait for the user to do something, or the CPU needs to stop and wait for some data to arrive from the database or the network, right? And so there's typically two ways for a program to do those kind of tasks, right? So to do IO specifically, we have the blocking or the synchronous style, which is, it's easy to write. It's what PHP and Ruby and Python and most web, especially server-side technologies are doing synchronous or blocking IO, right? And that's, and in order for that to work, we need multi-threading. Because if we stop one thread, we need another thread to be able to continue to serve user requests, right? And so, but it's easy to write because you write everything sequentially. However, there's a memory overhead to that because every thread requires memory and there's context switching. So when the CPU switches between the threads, right? So there's overhead there. The other sort of paradigm, the other pattern is the non-blocking or the event loop style. And so that's single-threaded. So everything runs in one thread, which means we cannot block the thread. We do get high concurrency and we get low memory. So that's the win. And it's really good for UI, so user interaction stuff, right? That's why the browser uses the event loop pattern. And it's also good for IO-bound services, things that are doing a lot of reading from network or database or disk, but it's not great for things that are CPU bound, right? Because anything that's using the CPU is blocking other things that could be happening. So that's kind of the overview of the two patterns. And so JavaScript, as you know, is the second one. And so all the browsers and most JavaScript server-side frameworks are all event-driven or non-blocking. There are some exceptions to that, like historically, like really older engines, but in general, every JavaScript you ever write will be event-driven, non-blocking. Does anybody have any questions about that stuff? So what happens if you block in JavaScript? Well, there are some things that will block the thread, right, that will halt any other execution. And so alert, right, is the most common, alert or prompt. And so we also have a synchronous style of XML HTTP requests and it's rare because that was probably a mistake in the API. They probably did not intend for that to be synchronous or at least it wasn't a good idea. And then we have some stuff in Node World that are intentionally synchronous for various reasons. But I think the one that everybody's probably familiar with is the sort of alert style where it blocks everything else that's happening. And so that's this one, right? And so that's like the page puts a dialogue up and everything pauses, right? You cannot interact or press a button, you can't even scroll. And so that's kind of a bad user experience, right? And so that's what we mean when we say a blocking interaction or blocking the thread. So how do we write concurrent software without blocking? So generally in JavaScript world, as you know, we use callbacks, right? And it's pretty straightforward. We just pass a function and when the task is finished, JavaScript will call our function. And that would be, for instance, an on click event. So you pass a function to the document, to the browser, and whenever a user clicks a button, then your callback gets fired, gets executed. Similarly, a network request, right? You're waiting for the network request to finish and then the callback happens. So this is the callback style, right? We're gonna read a file. This is more maybe server-side. We read a file. When the file's finished reading, we have our content. So does everybody understand the callback style? I mean, that's pretty much every JavaScript program you've written, right? So what's the good things? It's a good low-level abstraction for concurrency, for asynchronous actions. It performs really well. It has low overhead. There's not context switching involved. And we can do almost any asynchronous task using callbacks, right? What's the downsides? Well, doing things in callback style is really difficult, right? So doing things in sequence is difficult. Doing things in parallel is even harder. You give up your constructs that you're familiar with, like for, and while, and try, catch. And those are things that people come to JavaScript World from PHP background or from Java almost any other language, and they don't understand why you can't do these things, right? And so error handling, right? As you know, you always have to check this error parameter. Things could fail during the middle of a network request. It needs to be handled. And your code readability goes downhill pretty fast. So systems become kind of hard to maintain when there's a lot of callback asynchronous code. And so this is kind of the example of the first one, which is like the, or sorry, the giving up the constructs that programmers are familiar with, right? This is your typical example, right? So it's like every day on Stack Overflow, somebody asks, what's wrong with this code, right? And can anybody see why this code will not do what the programmer expects, right? So here we're defining an empty variable and here we're returning an empty variable. And then somewhere later, that variable will be set after the network request comes back. But to a programmer from a non-asynchronous world, this is a strange thing, right? This is a strange thing. And so that's why people new to JavaScript are always on Stack Overflow asking this question, right? So, you know, callbacks, they add complexity. It's messy to chain them, right? If you need to do three things in a row, simple things, right? Like write something to the console, wait a second, write another thing to the console, wait another second, and write something to the console. That's like a lot of callbacks, right? So it becomes messy to chain things and it's pretty hard to do things at the same time. And so this is your sequential stuff. And so this might be the most code you see on any slide, but I want you to get the idea of how the complexity grows when you're using this style, right? And we're not even doing any error checking here, right? This is like the simplified version. This is just taking three files and we just want to total the number of bytes in those files. So we have to read three things from disk, right? So we're gonna, so we're gonna stat file one, add it to the, add the size to the total, stat file two, add the size to the total, and do the same thing with number three. Every time we're getting more indented and then eventually we have our total and we can do our callback, right? And so, is anybody written code like this all the time, right? So if we want to do, so these three things, these three files, we don't have to do them one by one, right? We can just read all the files and then get the total number of bytes. So if we want to do it in parallel, it's a little harder, right? So this is kind of my naive version with no error handling of doing the same three files in parallel. So here we put the files in array, we for each and we stat each file individually, right? The problem is how do we know when we're done because the answer might come back in any order. So we have to keep track of the number that are finished and we gotta count every time one finishes, we gotta add that number and when we've reached three, then we know we're done, right? So this is kind of parallelism in callback world, right? And then there's error handling, so which we didn't even look at yet, right? So what do you do? Like we spent a lot of effort just checking if there's an error when we read file one but file two has already completed successfully, how do we handle that? And if we look at the same example with error handling, it doesn't even fit on a slide, right? Because now we have to like, if there's an error, we need to log it and return and that's not even good error handling. Like that's the minimum error handling just to log the error and just give up, right? And so we have to do it every time and so we have readability issues. So when readability is this bad, you know, systems become difficult to maintain, difficult to read, it's easy for sort of like errors and bugs in your code just to sneak in. So let's talk about promises. So we've kind of talked about callbacks, right? So promises do a little better. So this is basically a thin wrapper, a thin abstraction around callbacks. And so it gives us the chaining that we need, you know, doing task one, waiting till it finishes doing task two and continuing in sequential order. It gives us helpers to do things in parallel. It gives us error handling and they're composable, right? Because the way a promise works is we can pass around a representation of a future value. Right, so a promise is an object that represents what the value will be when the operation finishes. And so it kind of looks like this. So we read a file and then we get two things. We get then and catch. So then we can in a sense attach a handler or a callback that gets executed whenever the data is finished. So it's better than callbacks. Like it may not seem so at first. It may seem more complicated, but it is better. And so it looks, if you look at this code, like all we did was take our callback and put it inside of then, right? But we still have our callback. But it's better because we can do some chaining with that. And so I'll give you an example with, so this is a very simple function that uses setTimeOut and it just waits for 1000 milliseconds for one second and then it fulfills the promise, right? So it's the same idea as a setTimeOut, but in promise world. So the idea is that here we want to just wait one second and log something and wait another second and log another thing. And so we don't want all of that nested callbacks. So we get a better, more readable pattern here. So at least we can see first we sleep, then we do this thing and then we do this other thing. And then lastly, we do this final thing. So at least it reads in a very sequential order. And so the first thing you might notice is that we're returning something from inside our callback, right? So inside of our then handler, we're returning another promise. So remember, whenever we call sleep, it returns a promise that will fulfill or will finish in the future. Resolve, it'll resolve in the future. And so when we return a promise from in here, that's what allows us to call another then. And then the last one, we didn't return anything. So we're finished, right? So even this, right? Might be a little better than callbacks, but you know, it's not amazing. But we get flow control. So when we go back to our example of doing certain things that we have to do in series, we have to wait for one to finish and then do the next. Other things we wanna do in parallel at the same time. And so that's really hard with callbacks, but it's easier with promises. So the example would be, we wanna fetch some data about maybe the user that's logged in right now. And then we're gonna get back, we're gonna get back this user object. And then we wanna fetch the friends of that user. And then we'll return that promise, right? So every time we call fetch JSON, we're gonna get this promise. And so we'll return that promise. And then when that finishes, we have the IDs of all the friends. And so now, and this is where it becomes powerful, is now we can take these IDs and we map through them. So we go through each individual friend ID. And we wanna fetch the user details of that friend. And what I do here is I actually create an array of promises. So each time for each ID, we return a new promise. And since we're calling array.map, we get a map, we get an array of promises. And then we can call promise.all, which just waits for them all to finish, gets all the results, and we can return that promise. And then when we're finally finished our last then, we have all of the details for all of the friends in the order that they were provided, in the same order that they were in this array. So promise.all is the magic that I want you to understand from this slide. So here we're doing something that would be really hard in callback world because we're doing the first two things in sequence, right? They have, we can't get the friends until we get the user, right? So we have to do some things in sequence, but other things we can do in parallel. So that's the power of control flow with promises. So promises, even though they don't seem great at first, or at least when I first learned them, it seemed like a not much better than callbacks. Once you explore the chaining and the control flow, it is better. So error handling, we get a catch. And so we don't have to check every single time for this error. We can just attach one catch function at the end. And so exceptions will bubble through our code or bubble up the way we expect it to work in normal programming with try catch. So in this case, if we go back to our same user profiles example, I can just add one catch at the very end and grab that error. And we just know an error happened somewhere in one of these an error happened. All right, everybody with me so far? Cool. But we're still putting callbacks inside of then, right? I mean, we're still doing callbacks. It's a nicer way to do callbacks, but ultimately we eventually have to pass these functions. So can we do better? So what do we wanna do? Like we wanna just like have normal sequential programming like we're used to in other languages. And so here's what we want, right? We want to get our promise. We wanna somehow wait for the promise to finish and then we just wanna log the result, right? With no then anywhere. And so the problem is, JavaScript is fundamentally single threaded. So we can't block. And what I mean by that is, we can't just pause the program right here, wait for the promise to finish and then resume because we don't wanna block our entire thread and then you have the same problem as when you use alert and then the whole software is just not doing anything useful. So JavaScript is single threaded. We can't block, however, there's a special thing called a generator function. And so what that is, is that allows us to pause just one function and we'll go back to it later. So we're not gonna pause our whole program. We'll just pause this function. And so has anybody used or seen this generator syntax? With the star. So that's the special thing right here is the star. And then the keyword yield. So generators are not about asynchronous or event loops or they're not about doing concurrency. They're just about pausing stuff basically, right? So we get this thing called yield. We can just wait. So the idea is we just pause the execution of just this function. We wait for something and then later we will be resumed and we just console.log the string that says we're back whenever somebody has resumed us. So there needs to be something controlling this. Some function needs to resume this whenever the fetch has completed. So generators are pretty complex and I don't wanna spend a lot of time on them. I just want you to know that generator is the only thing that kind of allows this to work because we can pause our function. And it's important to understand it just pauses this function, not everything. So we take promises, we combine it with generators and we get awesome stuff. So this is the whole point. We get a single weight. So it's basically just a layer of syntax on top of generators and promises. And it looks like this. So instead of a function star, we have this async function but it's really similar to that function star, right? We use the word await and we put a promise after that. So await and then a promise and it always has to be that way. And then what that does is that await will pause it in the middle of executing this line, we just pause the whole function and we just wait but we let the event loop do other stuff and then eventually when this fetch has completed, this function gets resumed and then we have our result and now we can just console.log the result. So this is the whole idea of async await. A few things to remember. You can only use a weight inside of an async and it has to work with promises. So it's a win, it's a win because we get back our traditional constructs, right? We get back our for while, our try catch, it becomes readable. I mean, it's got some keywords in there that might seem strange at first but it flows like normal programming in any other language and normal thread blocking programming, right? And we get this kind of interop with promises. So we can use any other promise library and use it with async await because it just uses promises. So the same example or a new example of reading a file here with async await is that here we just use this read file which is a function that we've kind of made up that presumably just returns a promise and then we just wait for that and we get our content and then we convert it to a string, we parse it with JSON and we log the result. So it just reads sequentially like you'd expect and the point of this slide is that now we have our try catch back. So two things could go wrong here, right? Something could go wrong with the reading of the file, the file doesn't exist, the USB stick has been unplugged, the permissions aren't there. So this thing could fail. The other thing that could go wrong is parse. There was invalid JSON, it just doesn't, the JSON.parse can't handle what the file had in it. So these two things could have gone wrong and so this thing is going wrong in async world, right? Something is happening asynchronously while our function is paused. But this exception is just a traditional normal regular JavaScript exception. And async await doesn't care. The try will work exactly how you expect it to and it will send the error to your catch no matter which problem happened. So we can kind of not really think about async callback errors being different from any other error. And so we also get back our for loop, right? Things that are just normal programming constructs that have been around since the 70s and we understand them. And so in this case, we're combining just a regular for loop with async await and we get something really cool. So in this case, we just take a regular browser element and we're gonna loop through 100 times and move it a little bit to the right. By increasing the left value by one pixel every time, we're just gonna increase it to the right. But we wanna do it every frame, right? It's an animation. We wanna wait in between the frames. And so we're gonna wait 16 milliseconds between every adjustment of the value, of the style. So in this case, in like four lines, we've written an animation with 100 frames that happen 60 frames a second that would be really difficult to do with callbacks. But because async await just pauses our function in the middle of a loop, it just does what we kind of expect it to do and it's understandable. Does anybody have any questions about this? So it's just promises. And async function itself returns a promise. And so when we await a promise, our function pauses until the promise is ready or until it's resolved. So we can still use our normal promise stuff, right? So promise.all, which we talked about earlier, still works with async await. And here's an example of that. So here we're gonna fetch our, we're gonna get our user and we're gonna get our friends and then we're gonna map over our friends and create our array of promises just like before. But in this case, we're using await for both of the first things because we can't do the second thing until we've finished with the first thing, right? So we have to wait on those. But these promises, the fetching the friends, we can do those all at the same time. So we just create an array of promises just like before we call promise.all and then we await that. So we await them all to be done. So we just, so we, as long as the thing on the right of the await word is a promise, everything's cool. So the thing on the right needs to be a promise. And then, and then we console.logit at the end. But the thing I want you to know about this is that this whole entire function because it has this async word itself returns a promise, right? So if I call the function get user friends, if I call this function, it returns a promise. Yes, yes you can. You can await another async function because it's just promises. So a few pro tips, don't forget to use your await. If you accidentally leave out this word because you're so excited that everything is like, normal programming again, that you kind of forget to leave out the await, it's not gonna do what you think it does. So don't forget your await. Be careful about doing too many things in sequence if you can actually do them in parallel. So now that we have our for loops back that we love, it's very tempting to just put a weight inside of a for loop. And we have to remember that if we do that, it's gonna pause that for loop every single iteration. So don't do too much in sequence if you can do it in parallel. And so the other thing is that using a weight in a map or filter function probably doesn't do what you expect. And so I should show you an example of that, but the idea is that a filter function, right? A rate of filter should take a function that returns a boolean. But if you pass an async function, it's gonna return a promise. And so probably not gonna do what you think it does. So you just have to remember that. So map, it's fine to use, but just remember that if you pass an async function into map, you're gonna get an array of promises, which might be what you want. And so even though it looks synchronous, also remember that your code has been paused and then started again later. So some of the assumptions that you might make about global state or global variables might no longer be true after your function has been resumed, because things have changed in the world while you were paused. So user input, right? It's been traditionally hard with Node.js. If you've ever written a CLI tool, you need to read some data from the user and then you gotta have a callback and then you gotta read more data from a user and it becomes really nested. And so this is just our final example. It's just that we can just create a read line function that returns a promise and we can now await it and write command line programs just like you would in Python or any other language. But we get all the advantages of Node as well. So you can use this today. Async await is in Chrome, it's in Firefox, and it's in Node. For any of the other browsers, you should use Babble, but it's actually not that bad to use Babble because async await is a pretty thin layer on top of just generators and promises. So most browsers support generators anyway. So there's not too much stuff that Babble needs to do to make this work. So thanks for listening. Does anybody have any questions? Is anybody use this stuff? Has anybody used this in production or yeah? A little bit? Oh yeah. I have a background for back and forth and in the finance department and the double screen below here, I've been facing many cases like using promises instead of all that out, which we could use. But since I'm using Angular and it encores us to use the observable, I think it's better than promising since it gets many points. Async that we don't really have to write because the function looks already run by itself. There are certain things about promises that I would like, like whenever the function is re-learning the promises, then I need to run another promises to get that value instead of using plain variable, yeah, that's all. So I think it sounds like what you're saying is when should you use it and when you shouldn't use it, kind of. And so in Angular, you shouldn't use it because they've already built that around observables. And so another example would be onclick stuff. Like you don't need promises to do onclick handlers, right? If onbuttonclick, I want to console.log or send something to display something on the screen, I don't need promises for that. I just need to attach a callback, right? So observables are a totally different abstraction. And observables are about handling events that happen multiple times over time, right? So clicks are an example, right? A click doesn't just happen once. It happens a lot of times. It can happen a lot of times. So observables allow you to filter that and map that and do really powerful things that promises would not be the right tool for that. Because a promise is designed around something that gets a result back around a server request only gets one result back, right? It doesn't happen a lot. I mean, you can send a lot of server requests, but there's not a lot of results. There's only one result, right? And so that's what promises an async awaiter for. So I would say you gotta use the right tool for the job and I do agree that observables are the right tool for the job sometimes. In the case of what you were saying about then and callbacks, I totally agree that that's not ideal. So like some of this stuff that we were looking at here, like what you were saying, you can't just get the result into a variable. You have to do all the then stuff. And that's what async await is trying to solve. So I do think that it will solve half of your question. Yeah? Yeah. Right. Yeah. Bluebird is good. Yeah. And it's the fastest out there. In fact, Bluebird is faster than some of the built-in browser versions of promises. They're just really fast. Yeah. And so that guy has a pretty good talk on performance. But yeah, so, so Bluebird is a good choice. Yeah. And generally though, I mean, I use promises because it's a standard. It's becoming a standard. It's built into the browser. A lot of the browser stuff like fetch. And like if you're in the browser and you want to get the battery percentage of the computer, you need to use promises for that. Because JavaScript is just moving towards promises, even the built-in functions. So yeah. Right. So if I learn more about your use case, there might actually be a good way to do that with promises. Yeah. I mean, I don't know. So we should talk after or shoot me a message. But yeah, I mean, there might be a great way to do that with promises. Or maybe promise is the wrong tool for that task. Right? So anyway. OK, cool. Thank you. Yeah. About error handling, do we need to use a promise project or just use things like throw or any JavaScript error handling? So you can do both. You know what a good way to explain that would be for if you're creating a new promise, if you're using. So nowhere in my slides did I use the word like new promise because generally those are library stuff. Like you expect your database library to already create the promise. You expect your fetch library to already give you a promise. And so if you need to create your own promise, then you have to use reject. But if not, you can just throw. So I guess that's a low, to answer your question, that's like a low-level tool. So that's something that library authors would use, whereas you probably don't need to use that if you're just consuming promises. Is there any limitations when you're using promises? Like how many are different, the number, the number? Yeah. So promises are not as, they use more memory than callbacks, but it's not a lot. So most of the time you don't have to worry about those limitations. So if you're on a low-end device and you have a very large amount of things happening at once, even then I don't think you would have a big problem with memory. The limitation that I know about with promises are they're not cancelable. You cannot cancel a fetch. So if you fetch data from a server and then you realize you need to cancel that, there's not really a way to cancel a fetch request. And so there's a reason for that. The people who built promises, they didn't want it to be cancelable. Because if you think about, for instance, what's our example like this one, in normal programming, if there was no await there, you can't really cancel a task in the middle of a line anyway. So promises weren't really built to be a construct where you can just cancel a request. But it is a limitation, right? They're already used testing await in early 2016. And there are also some early developers of this. And this is actually drafted for the S7 right in 2016. So what could possibly be the next expansion on S7 in a week? Right, so maybe streams, maybe some way to handle streams. So for right now, if there's some ongoing talk about what to do if we're, let's say, instead of fetching JSON, let's say we're fetching a JPEG. And that JPEG is big, and we want to handle it in chunks so as not to put it all in memory at once. Like this whole paradigm here doesn't work with that, right? This is about doing the entire task at one time and then getting the result. It returns a promise for a piece of the data, and then you have to do something with that data and then send out another, tell it you're finished, and then you get another promise. So it's a little strange. Can I show you the, sorry? What is CodeFox? Yeah. Yeah, so I'm glad you asked. I would love to talk to you about CodeFox. So CodeFox is, so we're a dev team, and we're about one year old, a little over one year old. And so most of the CodeFox guys are in the back corner there, so CodeFox did. And so we build mobile applications specifically using React Native. In fact, we do kind of everything React in JavaScript. So we use a lot of Facebook tech. I was at Facebook previous to CodeFox, so that's where kind of I learned React. And we were using Async Await when I was still there in 2015. We were using GraphQL, and we were using Flow, the type system Flow. So we've kind of built our company mostly around Facebook tech. I mean, we use like Jest, even, which is from Facebook for testing. So we use a lot of Facebook tech. And it's all just open source stuff. And I'm probably a little biased, but I feel like it's really good software. So yeah, so we build native apps in React Native using a bunch of pretty modern and cool tech there. I heard about the license issue about React Native. Yeah. Like if you build something that goes a bit with Facebook, it feels real. Yeah, I don't know enough about the details of that, but I can say that I'm not really worried about it. And a lot of the big companies that are using React, like Airbnb and Netflix, and even Microsoft is using it, they aren't too worried about it. So I think it sounds scarier than it is. And so the big companies who are using that have really good lawyers that are looking through the license agreement to figure out what they can and can't do with it. Ultimately, I think that that was probably put in place for them as a protective measure from patent lawsuits, because the bigger you are, the more likely you get sued, because somebody knows that you're likely to settle out of court instead of dragging through court for 10 years. And so Oracle sues Google, and Google sues Samsung, and Samsung sues Apple, and they all just kind of sue each other. And so sometimes their best defense is to have something like that in place that says, like, if you patent infringe me, then I can reverse sue you for using my open source framework and something like that. But generally, I think it's a defensive measure and not an offensive measure, I think. Just a quick one about the promise. The promise is a pretty good way to put it, yeah. So an observable is something that can resolve a lot of times. And a promise is something that can resolve once. The difference is that observables kind of treat time as a parameter, right? So you can, I might not be explaining that perfectly. We don't use a lot of observable stuff. My understanding is that you treat a series of things that are happening in time as if they're a series of things in an array. So you kind of do functional stuff to those. So I think that that's probably a good explanation. But in reality, they're used for very different things. Yeah. So actually behind this is because the technologies are actually different from ours. Yeah, I mean, they're all just using callbacks, I guess. So that's why callbacks is kind of the primitive building block to build better abstractions. And there's lots of cool abstractions on top of callbacks. There's, like, if you think about GoRoutines, or we have sagas in Redux World. And so a lot of these things are about running, like handling concurrency in different ways. Cool. Yep. Thank you. OK, thank you.