 It is Thursday. It is 2.30 PM UTC. It is time for Supercharged. Hi, I'm Surma. Hi, I'm Madiko. And we are going to do some web workers. Let's go. So web workers. Usually on Supercharged, we do more like bleeding edge technology things that only work in Chrome Canary with like the web platforms flag enabled. But today, with web workers, we're actually using something that has been around for years. Yeah. And many browsers, I think even Internet Explorer, multiple versions have support for web workers. So you can follow along in whatever browser you are today. And that's new. So Mariko, welcome. I'm very happy to have you here. Thank you. Before we dive into code, I think we should make sure that everybody, I'm not sure everybody knows what a web worker really is. Yes. And even I'm not sure if I know the right definition of it or what. Can you maybe bring us all to speak? Oh, OK, cool. Sure. Should I do the picture? If you want to. So what would you describe a worker? If somebody asked you one line. I would basically say it's an actual second thread for JavaScript, like proper parallelism in JavaScript. And then you have some very simple ways to communicate with your original main thread, as it's called. Right. So this one. I had that explanation given to me. And I was like, what do you mean thread? JavaScript is a single thread. Exactly. And that's what already confuses people, I think. Yeah, yeah. So when I, so I discovered web worker when I was trying to make the very similar app that we're going to try to make today. And I wanted to make a performance. Then I discovered web worker. And I was like, what does that even mean? It was like a little confusing. So I pictured it for you. I drew a picture. You are known on the internet for drawing explanations of things. So I'm very happy that SuperCharge gets to enjoy these drawings of yours as well. So imagine that your browser is a planet or something. You might know when the garbage collection is. You know, the garbage day schedule is garbage collection. You know all the elements on the planet because HTML elements are there. The web worker, you can think of it as something like international space station. It's something that you create from the browser, the planet browser. You launch it. I like planet browser. Out of the world. It's outside of the planet browser. But then from planet browser, you send the data to do all kinds of scientific exploration that happens. So they can do a lot of tasks. But because it is outside of the planet browser, they cannot touch the elements on the thing. So in the web worker. That makes a lot of sense. It does not have a lot of access to window object. It does not have access to document object. Basically, you cannot do anything that touches what's on the screen. But you can do a lot of JavaScript. True. And that's what we're going to use today. Yes. And so this was the first explanation probably of many to come because we are introducing some new concepts. But if you have any questions, you people watching us live in the chat, ask them because I'll be monitoring the chat or the hashtag SuperCharge on Twitter or my mentions on Twitter. And I'll try to forward them to Mariko because she is the expert in all of these things. And she will hopefully answer your questions, even if they are, about coconuts, Jake. Thank you for making sure that people believe us that this is actually live. So where should we start? Well, coconut? I'm sorry? Jake said in the chat that I should send about coconuts to prove that this is live. Oh, yeah, by the way, somebody who doesn't know Jake is our colleague who is literally sitting above behind us. He did a live stream with me two months ago, three months ago, about service worker. Who would have thought? OK, so as I explained, in order to utilize WebWorker, you kind of have to have a lot of JavaScript to do. Something that is not changing the visual or making a DOM element, it's a lot of JavaScript. So I have a plan for today that I kind of thought of. So I know Matt did last SuperCharge like an image processing thing in WebGL, but I don't know how to speak WebGL, but I know how to do 2D canvas. So what if we do a lot of image processing in 2D canvas, and you do basically image filters, do a lot of using the bits thing, and then that involves a lot of. The bits thing? That thing, yeah, that thing, the pixels thing. If you don't know what we're talking about, I recommend you watch the previous live stream after we're done. Like, watch us first, then watch the other one, because we have many live streams on this channel, which you also should subscribe to. So here's the very simple diagram of what's in my head. OK, this is what we're going to build. So I'm going to have an input button that opens up the file dialog. So it's like, I want to edit this image, right? That is loaded into the screen. And when that gets loaded into a screen, it does something. Let's say, it's kind of like an Instagram filter, right? Like, you know, let's make it like a black and white or like, you know, any kind of image processing. And then, display it on the screen. Because I suspect that doing those filter thing involves a lot of computation. And maybe it's a good example to put it into obokers. So let's get into first making that application before even we talk about oboker. Yeah, let's go for it. All right. So I have index HTML, and I started a simple server that is serving that file. So let's say, let's just see, like, you know, I'm not lying. Let's say, hi. And then if I reload it, it just shows up as a hi. So that's working. So for now, let's just say, title. And we're done. See you next time. Supercharged. Oh, you're even on brand. That's so good. Emoji. And then. No, it's one word. Thank you very much for inviting me. So as I mentioned, I need to have input button. We have the first question for you on the chat. What do you use to draw your diagrams? I use iPad and Apple Pencil. Do they care about the app that I use? There's a bunch of app that I can recommend later if you want to do it. Speaking of, follow Mariko on Twitter as well. If you have more drawings, that's the place to go. We have the link in the description. Cool. So when you have an input element, you can specify what kind of input it is. And in this case, we're going to use file. And then when you are doing the file input, you can also specify what kind of file this input accepts. So accept. And this time, we want to only deal with the image. You don't want a user to accidentally load JSON file or something. And just like L or everywhere. Let's do that. So image out. Image. And then let's say star. So that in PNG, JPEG, Bitmap, anything accept it. And just have it in. Also, it uses the MIME type, not the file extension. OK. ID input. Because people, someone brought up that we are missing some meta tags in the header, that is a good opportunity to mention, this is my production ready code. This is only supposed to work on Mariko's screen just now. It's more about the concept. She's going to use and explain to you. You can then later on go to our repository on GitHub, grab the code, and add all the meta headers that you want. PRs welcome. That's a good PR for PR. Exactly. So choose file or something. So if I have that, well, I should have four inputs. And then let's lead all this file. And then I have filing, but right now it's very small. So make it bigger. If I click it, the file dialogue opens up. And then I can select it, image, and then open it. And then nothing happens. Nothing happens right now. Why would it? You haven't written anything. Nothing, you haven't written it. So let's, before I begin, so do you have this thing where you start doing this and then unless you style it somewhat nicely, you can't really move, because your motivation is not. No, I'm the exact other way around. I hate making my things pretty. I just want to get the core functionality done and then hand it off to someone else. So as you can see, I'm a visual person. You don't say the person who draws on Twitter. I mean, I'm not like no way like a designer or anything, but like I'm definitely drawn to like visual, like shiny things. So let me just style it quick. Yeah, go for it. I mean, I'm just going to style it bluntly. You can take questions or. I guess I can actually. First of all, I have a question for you. Oh, a question for me from the. I want to have a ID selector on my CSS. Yes. This keyboard does not seem to have a. So you are actually usually in the New York office. Yes. Not here in London with me. She just came over to visit specifically for this live stream, specifically for this live stream. So she's not used to UK keyboard. Shift and three is the combination for. Oh, that was a cat block. There we go. I'm sure I'll ask you. On the American keyboard, you have a separate key for the hashtag, right? Well, where the British pound sign is, it is already listed as a pound. I see. I mean, pound, but like pound meaning like a hashtag. Not our currency. Words are confusing. All right, keep styling. Styling. I wanted to quickly answer Tim's questions from the chat on the video as well. Because it is interesting. We have been talking about modules on the Chrome Dev Summit pretty much recently. It's been on the top of the topic list for many frameworks switching over to modules or supporting modules. And since we're going to use workers today, it's probably important to mention that no browser yet has support for modules in workers. The syntax has been specified how to load a module in a worker, but no browser actually implemented it. That's something that I guess all of us have on the roadmap. But I'm also assuming it's not a very high priority for most browsers, because very few people actually use workers, which is what I'm hoping to change with this live stream. So maybe after this, we can exert some more pressure on the browser people to speed the process up a little bit. IPX. So we have some more colors. Yes, let's make it font size bigger. I never use the EM type. Maybe I should use it more. Yeah, that looks good. So what I did was I hidden the default input button, and then I made the label part as a clickable. That's a good old trick. You have to be careful with accessibility on this one. So I prepared for this. I care about this thing. I do front end development. You go and explain this. So right now, if I tab it, I can't get to the input element, which should be able to, because it is an input element. But the one that is focusing input element is basically zero-waste-do-waste overflow hidden that's completely hidden. And it's just a display is taking over. Practically invisible. Right. So I need to put a focus to this element. So again, what? Also, when the input element is focused, you're going to change the style of the label. That's tricky, because what a lot of people do is actually display none the input field. And that is very bad flexibility, because then it becomes non-focussable for people who use screen readers. So this one is a different trick where you make it invisible by giving it a zero-by-zero size and then making sure the styles are propagated from the input field to the actual. So I kind of cheated because I couldn't remember the order of, like, pixel, order, style, and thing. But let's see if this works. So if I tab it, yes. Nice. And then tab out. So now I can select it. So now I can see this is selected, enter, and then follow. Cool. And then select it. So cool. Now we have something, something to start with. And that's pretty much the only UI element we will have on this. Sounds good. Now we have to do something with the image. Yeah, let me just change the color. This is not fun. Color, let's say, F3, F3, F3. You're just making those colors up, aren't you? Blue is not cool. Teal. Yeah. Let's go with that. OK. So now we get into JavaScript part. So the input element, the native element, will let us have the model for the file and then let us give the information about the file that we selected. But we need to access that, and we need to write a JavaScript for it. So let's write a script. And I apologize. I'm going to put everything on index HTML. Yeah, that's how we wrote here. No worries about that. So let's do the JavaScript part. Look at that auto-complete. Ha. Don't you think my subline setting is superb? We haven't had subline on this stream in a long time. Have you heard of VS Code? Yes. Just to be clear, before a flame war starts in the chat again, your editor is fine. As long as you press a key and that character appears on screen, you're set for web development. I don't care about anything else. So if you use WebStorm, if you use Sublime, if you use NotePlat++, it all works for web development. So don't ever get feel discriminated if you use a different editor from what you see other people using. Yep. So while Soma is putting the disclaimer about the editor, I just put the. I like the shout out to the old jQuery syntax. Oh, so this is what I do. So whenever I do reference to the DOM element or HTML element that is already existing in the screen, then I, even though I don't use jQuery, I just put the dollar sign so that mental note of like, you know, I can see like which element still, which element objects still lives in the memory and then which one is actually displayed on the screen. So in this case, input is already on the screen. So I just put the dollar sign and add event listener. So change event is fired whenever user selects different files. So another apology. I'm going to console log the hell out of this code because that's how I code. That's how the professionals do that. I think that's perfectly fair. So let's see what kind of event data that we get. So let's tab, select picture. Oh, I need to do the DevTool, don't I? Inspect, console, something is wrong. Oh, capitalization of that function call is always weird. Consistency, something that we don't have on the web. All right. So we got an event. Then usually, you know, usually it's like in the target where you want the data to be, right? Yeah. And I just happen to know that if it's file, in the target, there will be files. Ah, so we actually get, and that's where all of that information. And that's an actual file type, so something you can read. So the name of the file, like, that's actually really interesting because by the user selecting a file is implicitly granting you as the website the permission to read that file. So we are already done. We can now read this file and work on it, which is what we want. So that's cool. So let's say the file that we want to access will be const file equal in.target.files and then the first one. Now, now we have access to all the information, but we have to actually load it in the browser. Yes. We only got the metadata. Yes, like an object representing the file, not the actual contents. The browser hasn't figured that out. So in order to do that, we make a file leader. Oh. I have touched on the file reader API, not on stream, but I have used before. It's not the nicest API to use, but I guess you'll see now. So file leader is the name of the, as it suggests, it just reads the file and it comes with a lot of methods to lead. So one way to lead a file is lead as data URL, which basically returns the basic, if it's in as basic 64 representation of the file. Okay. So I created the file leader here on the line. I guess it's interesting to note that, like most of you probably have seen data URL somewhere, like when you inline a little icon in CSS. I think in most browsers, these are limited to two megabytes. So if you want to use, in this case, we might want to load a bigger image later on. So that would probably not be a good choice for us. But we're going to start with it. Yep. So, and then once you lead the file, you have to do something once the leading is done, because it is, you know, done, what do you call it? Like asynchronously? Yeah. You basically have to listen to on-load event. Ah, yeah. I would add a file leader, the event listener, oops, and then load. So somebody asked why are you using const? Is it necessary? That's a good question. I don't know. I started using const. I started basically ditch every var. Exactly. So I think on some stream previously talked about this, they used to be, everything in JavaScript used to be var. And now there is let and const with es2015. And I mostly use const because it signifies to the next person who reads my code that the value of that variable is not going to change anymore. It's just something that makes, like you have to juggle less state in your head when you read the code. So I try to only use const and let. And also the advantage is their block scoped rather than function scope, which in JavaScript is the default and very confusing at times. Yep. So I just created a file leader, lead it as a data URL, pass the file, and the file leader, I added an event listener for load event. So now if I load it, I get the event back. And inside of the event, again, and then the target, I get the result here, which is a day 64 representation of the image that we loaded. It's beautiful. I can practically see the image. So let's say const image data. Well, that's going to be confusing. So image is e.target.result, right? So now we need to somehow put this data into the browser so that browser shows an image, right? Yes. The easier way to do it is making an image object. So again, image, new image. Ooh, ooh, ooh. I just neatly deleted the semicolon. You made a call recently about my code. I did. I personally am a big proponent of using semicolons in JavaScript. Mariko's not. I disapprove. I don't have any strong philosophical belief or anything. I just walked in the company for two years that. And I think that's the thing. It's mostly acquired cases. The way you start coding is the way you're going to keep coding. I mean, if somebody makes me like, you know, let's say our team decides everybody should write semicolon. I would happily adapt it. But there is nothing, no mandate here. I mean, we have a Google ESLint configuration, which will demand semicolons. But, you know, I mean, I have ESLint on most of my projects. But for this, supercharged. Is our production ready? Go. So who cares? I created an image object on line 31. And then now I assign the B64 representation of that. Oh, let's say this is base64. And then SRC, much like the attribute on the image tag. 64. And now, once this operation is done, then the load event will be fired for this image object. So once that's done, I need to append that image object into the screen, right? So let's check if this works. So document.body.append.joiled.image. And let's see if this works. Click it to click. Yay. We just loaded an image with a file selector. Yeah. That's pretty damn cool. Yep. For the reason that comes in later, I'm going to leave this in div so that it does not. Again. You can always add divs. I just need to kind of like, I'm not a designer, but I need to style something. OK. Whoops. All right. So now that we have a user selector image, data image is gloved from the memory, put it into browser. Let's put it into so that we can apply the filter to the original plan, right? So I guess you can do that on the image element but you need a canvas. Yes. So image element is great, but it doesn't have a finer way of like tweaking and things. I know you can use a CSS to put like a filter. But that's not the point today. But like, you know, yeah. That is like very specified thing. And that's not the point. Like, you know, that is like offloading our mass problem to CSS. Like we want to do the math on the JavaScript so that we can use WebWalker. So let's make a canvas where we just recently published an article about how expensive a blur is and that if you animate a blur, you will probably see a lot of jank. I'll link to it in the description later on if you want to read that. And you should because I wrote it and I would appreciate you reading my articles. I did. It was wonderful article. Yeah, so that's, and the point is today we're going to use a WebWalker eventually to offload heavy work. But that article basically explains why a blur is so computation intensive, even though it is like a simple effect in terms of what it looks like. Okay. Context 2D. So I suppose I should explain this part if like somebody have not done canvas work. Yes. So canvas, much like any other HTML element, you just create a canvas tag, right? An element. Yeah. And then you can reference it by ID or class or however you would do. Type of the ID. Oops. What? The V is missing. Oh, VU. What? A DI. There you go. So that's what's happening here, a dollar sign preview. However, in order to do a lot of like computational work on canvas, you have to tell kind of like define the language that they are speaking. So going with like a planet explanation, let's say you decided to, I don't know, your master creator, so you decided to create this planet, right? Yeah. And then you decided to... As you're known to do on Friday. You decided to speak, I'm going to speak this one language, which is WebGL. Yes, which we did last time. So you would say, you know, the WebGL use specific thing called shader, and then that's how you communicate with this canvas planet. In my case, I want to use 2D, which is another set of language, and that's called context. So whenever you define that language part of the canvas, you call getContext, and if you're trying to do the shaders, you would say WebGL, but this time I'm getting the 2D context. And basically, preview CTX context. Context is the one you interact. That's the actual manipulation API. Yep. So like, you know, the canvas, you can maybe set the width and height of the canvas, and that's about it. That's pretty much it. Yeah. Like if you do WebGL canvas, you get, you know, all the functions to load triangles to the GPU, to upload textures, and in this case, you get functions to draw lines, draw circles, whatever you want to do as a 2D operation. Yep. So instead of loading an image as in child element, now I put an image into the canvas and call the method that canvas has, which is drawImage, which basically takes an image element and put it into the canvas. So let's do this thing and see if it shows up. Oop, hello. Oh, okay. When you're drawing the image, your first argument is the image object that you're putting to, and then you need to give the location where you want to draw. I wish that was just half sensible defaults, but sadly, this function does not. So I want to draw four sides. So I would say the top left corner has to be 0, 0, x, y. So 0 and 0. And hopefully, this should draw a picture into canvas. Hey! So... I mean, part of the image is missing, but you know, that's good. So it's inside of the canvas, right? It's not an image element anymore. So I know why this is missing because we only cleared it canvas and default size for canvas, I think it's 200 pixels by 400. I thought it was 300 by 150. Oh, maybe. Like an iPhone. I only remember 1 by 2. Yeah, it might be true. Yeah. So we just need to set the side. So in here, I would say preview with the name of the canvas. So preview with... Ah, so you're going to resize the canvas before drawing the image, which means of sense. Because a lot of people, apparently, are very interested in the soldering iron. It is real. It's just not switched on. And why would it be? It would just be dangerous. Solving what? The soldering iron. Oh, yeah. Yeah. It is real. I'll tell you that. There we go. So now, shows up on the grid screen. All right. Let's just maybe... I'm going to do really bad technique of putting VR. I'm disgusted. Because all I care is how it looks. And that's how bad websites are born. Welcome to Supercharged. Does it even work? Yeah. Of course it does. Later, if I was pushing this, I will clean up with nice padding and everything and check with designer, but for now. Right. Ah, what I need to do. Oh, yes. So now that the data is in canvas, we can also get the data out of canvas. We can read back the pixels. Yeah. So let's just switch up this thing and make it like a function. So apply filter is a function, and then we will have a separate function. I was about to say it's a function that you're going to write. It's not a function yet. Right. Now it is. Oh, I can type. You have the excuse of having to type on a foreign keyboard, not only in terms of layout, but also on our streaming laptop, which you probably have. See, this is the thing. It's not showing up, but the enter key is so small on the British thing. It's bigger than on them. Ah, I guess it's taller, but narrower. Yes, yes. While on the American, it's like wider. And whatever you're used to, you will totally mess up once you're on the other keyboard. It's horrible. When I go to America, I just, I can't type anymore. And for you, it's basically the same just now. Yeah. So Canvas has this very handy method called get image data and put image data. You wrote with here, I think. Oh, how did this work? Just by coincidence? Probably. Love it. Maybe, yeah. All right, all right. Apply a filter. In order to apply the filter. Thanks for the chat. In order to apply the filter, you need to get the chunk of pixel data and then you need to analyze those pixel data and then change something about that pixel data. Right now, we only interacting with the HCM element. We don't have that data element, right? So in order to do those, Canvas has a method called get image data and put image data. Yeah. So the easier way to explain to me is like this. So imagine this is a canvas, right? You have a canvas. You go through context, right? Context start called get image data. Yeah. And then you get on the parameter, you can specify where that should start and how big. So you can like, you can get like a sub rectangle of the entire image. So you have like four arguments. Okay, cool. And then you get data and then make it pleady, the data pleady. And then you pass that data into put image data method and then put it back into the screen. Okay, cool. So that's what we're going to do. So basically we're going to take the image out, do some processing and then put it back in. Yeah. And that's how you do effects. Yeah. So let's see what that data that we've been talking about look like. Yeah. So say I already have a context. So play view context. Okay. Get image data. And zero, zero. And it would be image.Width. Ah, maybe we're using that. That makes sense. Yeah. Yep. And let's see. Cool. So what exactly is like what is the image data? Is it like a special type or is it just an array or? So image data is a special, I guess. Oops. It's an error. Image data is not a function. I think the I needs to be careful. Oh, yeah. So it's a special, what do you call it? Object or data type? Type. Okay. So you can see. So. Okay. Keep going. Yeah. They have three data in there. Yeah. Width and height. And then inside of that data, data is an array. And the array. It's typed array. Typed array. Yep. Array is a. This is the future. I love DevTools where I can like how many 360,000 element array and you can inspect every single one of those cells. So you can see here is the data of a whole bunch of numbers. Okay. But those are just numbers. Not really. Like. How do what do those numbers represent? So. Yes. This represents the image that's on screen here. Yes. Allotted on the canvas. But it is a. Allanged in the certain way. And it's like one dimensional whole bunch of numbers. Yeah. And the way I think about it is so the, it comes in the set of four. So from zero to three is a data you need to represent one pixel. Ah, okay. And you might have guessed it. It's all GB and alpha. That's why every fourth value just now is 255. Yes. Because we don't have interinsperency going on. Yes. Okay. So every group of four forms one pixel and then these four elements in individual groups form the R value, the G value, the B value and the alpha value as you might know from CSS. So you can probably handle that. One thing that changed from the CSS is that in the CSS if you do RGB A to set the color, the A, the last value would be zero to one. But in the canvas case it would be zero to 255. Ah, okay. Yep. Because the thing that we're using it is 255. So you may ask like, but it's flat. How do you know where imposition that it's located, right? So when you are writing letter to somebody I don't know if you do this in German. I suppose you grew up in Germany. So in Japan, if you're writing a paper or a letter, you would get this graph paper. So each square is for one letter, right? Yeah. So in my head I'm thinking in the one-dimensional way of like, hi, Surma. It's like one-dimensional. I wouldn't think about like, here's going to be line break or anything. That makes sense. So basically. And I'm going to write it from the top left corner. Say hi, Surma. And then once I run out of the space, I go to next low. I see. And then fill in what's in my head as a one-dimensional data, right? It's the same thing. So from here, the first fall is the top left corner. And the next one is the first low, but the second from the left. So it goes to the right until we reach the width, which we have in our image data object. So we know once we have 300 times four. All right. We go back to the first pixel, the next line. All right. That makes sense. Because we have the width and height and all whole bunch of data, we can deconstruct this. OK. And we know where exactly which number is four, which pixel, or which color channel. And now we can probably jumble around those numbers and make the image look different. Yup. So let's see. In order to do this, this is very tedious part. So as I mentioned, we were just like explaining this. We have to do this in code, right? OK. So. I'm smelling four loops. Yes. Yes. So four loops. So for everyone who has joined just a couple of minutes late, then we started. Welcome. This is Mariko. Hello. I'm Surma. We are, I mean we said we're going to do web workers. We haven't even touched the web workers yet. So far we have been loading images from the hard disk and drawing them onto a canvas so that we then can process them and show. I don't know. Not me. How would I know what we're doing? I'm monitoring the chat. So if you have questions, just put them in the chat and I'll try to follow along. We're very many people today. So it's kind of hard actually to keep track of where I stopped reading and where I have to catch up. But yeah, keep sending those questions. And Mariko will tell you how to do image processing in JavaScript and then later on, what web workers has to do with it. Yeah. So. So okay. We're doing the classical. Yeah. If you've done that with Canvas, this is like, you know, engraved into your heart that you are like, ah, yeah, yeah, yeah, you don't do that thing. But I will explain what's happening in a minute. There should be a synthesis and there should be D. So. Are you sure? Oh, index. And that's probably four, right? Should there also be a times and not a plus? Yes. So I'm a lost image processing. We have done this before. I mean, not us, but I have done pixel conversion on images before. Right. So what's happening is the outer for loop is X. So going through this direction and inner for loop is Y. So going through this direction. Yes. So in combination of those, we need to do. Every pixel. Every pixel. However, every pixel, remember, has a full values. So index has to be padded with four. Yes. So if we increase the index by one, we have to jump four fields. And that's why it's times four. Yeah. Okay. Can I show off my drawing because I'm leaving a cloud over it? I would love for you to show off your drawings. So here is the visual explanation of what I just said. Right? So the outer loop is the green. In this case, I actually did Y. Sorry. Doesn't matter really. Yeah. So the green one goes down from top to bottom. And then the orange one is the X and go from left to right. And then inside of that, you have index and you get to access each pixel by index plus one, index plus two, index plus three. Yes. That makes sense. And you get to something. Cool thing happened once you have access to those things. We're going to do the cool thing as well. Don't you worry. So let's see. Let's say changing opacity maybe. Yeah. That sounds good. Sounds easy enough. So the last one is the opacity. So alpha is image data that we have. Inside of image data, we access data. And then inside of that, index plus three is where all of the alpha channel lives. And then right now it's all 255. So I'm just going to set it to 272 or 27. And then let's see if I actually get to... Oh, I need to put back into the data. So... Okay. So now we have changed the fourth value in each pixel pack, the A value, 237, which is basically 50% opacity. And it's plus three because as always in program, we started zero. So zero is the first pixel. And so plus three is the fourth value. So I just changed all of the value, which is in the image data dot data, right? And then I put that data back here on this line. So hopefully this picture will come as a slightly opaque. Nice. We just have done image processing. Yep. So we can do... We can totally do the thing where... Let's see, it's changing the thing. I think Matt did like a warm... Yeah, he did a warm filter in the end. Filter or something. So R is the red value. So I think what he did was like increase that value a little bit to make it like a more... Yeah, I think he had like a factor and he would go a little bit, add to the red and subtract from the blue depending on how high the warmth value was supposed to be. Okay. Well, let's just do the simple thing of like... Red is where the first one, so index, right? Basically we're going to make Jake's face more red, which is what he looks like once he has seen the sun. True. Oh, that's a good one. And then times 1.1 or something. Well, 1.2, let's see. Right? So... Because the first is the red value, you're increasing the red value. Okay. And interesting fun fact, because the image data dot data is a clamped U and 8 array, if we go above 255, it will automatically stick to 255. Yeah, I love this feature. And the same with 0. You can't go negative with a clamped U and 8 array, which makes it super handy for this kind of image data. So choose Jake's image. Definitely more red. Definitely more red. You seem like nicely timed color. I never do in real life, though. So that's good. Yes. And this seems working fine. Yeah. But, you know, in real life, the photo we take on the phone is much, much bigger. That's true. I mean, this picture I think we saw in depth was about 300 by 300. Nobody takes those photos. No, nobody does. And I want to keep... I don't want to resize it to make it fast. I want to keep the original size. Of course. You basically want to recreate a photo. You don't want to lose quality just because you did some, you know, just some touch-ups. Yeah, yeah, yeah, yeah. So I have a big file, the cat JPEG. And once I open it, visibly, this is very subtle. Nothing happened. Oh, it just... Oh, so like it didn't not work. It just took that long to draw and process the image. Okay. That is a little bit long, I have to say. And also, we wrote this on the main thread JavaScript. So probably the browser just froze. Yeah. So let's like investigate, right? So you might need to help me here because I'm not an expert on the thing. But as I heard, you just hit record. That is correct. And then do something that you want to record. And wait for it to happen. Okay, so DevTools is still working. It still hasn't appeared on screen. There it is. Stop it. And let's see what DevTools says. DevTools says there is one massive red bar at the top. You never want to see those red bars because that's what we call jank. That is when the main thread is blocked and basically cannot react to user input, like scrolling or clicking a button. You never want to see those. If you do, you have a jank problem most likely and have to investigate how to fix them. Yeah. So that screen, so I think if you remember Paul Lewis, he always said you have a frame budget of 16 milliseconds. You shouldn't be doing any more calculation in your JavaScript per frame in 16 milliseconds. This was six seconds. That's too much, Mariko. Yeah. And to be fair, I doubt it will go down to 60 frames per second. No way. It's 2D canvas. The image is just that big. There's not much we can do about it. The image is just that big. But we can minimize it so that the user can have a kind of break point so that they can interact with otherwise. It's like a perception of the speed is faster. Okay. Fake it till you make it. That's right. That's what we call performance. Yes. So let's do this. The first thing that is very blocking, and it helped me if you can point it, loading the image part. I mean, there's the load event. Oh, that's when it's already loaded, right? Yeah. A function goal. That event is now. What are you looking for? The image loading part. I think, I suspect this chunk is where we, yeah, file leader. Yeah. We were leading the file. So I happen to know the, it's not that new, but it's newer than WebWorker. True. That. I mean, pretty much anything is newer than WebWorker, almost. So, do you know what it is that I'm going to use? Is it create a much better? Yes. So there are the, what do you call it, API? Yes. Or create image bitmap, which allow you to pass a file data and magically creates an image for you. So this will allow us hope also to not only make the image decoding be a janky process, but it will also avoid the file reader API. Yep. So I do not need file leader API anymore. That is so much better. I don't need to listen to the thing. I don't need to listen to the image. I still do, maybe. Yeah. You still want to know when the image. Right. But I can delete the file leader. And that's good. For sure. Create bitmap, create image bitmap is a promise based. So. Nice. Once things are done. I'm a big fan of promises. You call it with then. Mm-hmm. And then. Or an async function. Oh, we can use then. That's fine. It's completely valid. Saying. Do you want to do it? No, no, no. This is your code. If I would take over right now, the first thing I would have to do is add some my colons to every line. So we're not doing that. You keep coding. So bitmap. See. Now the return value from this create image bitmap promise should be the image, right? So you can append that to image.soc. Wait. No. No, no, no. You directly go to the camera. So let's just console like this. I don't know what it was. Yeah. So maybe you want to just see what kind of type you get back. Yeah. So let's just do the small one before we go into the thing. Okay. So, image bitmap. Just as hide and with. Done. And then I remember this API only exposed within height. To developers. As properties. But there can be methods. Yeah. It is a representation of the data, right? So I can directly draw that into canvas, I think. Because it's already image. And canvas already have a draw image method. Okay. So let's see. I take this code here. And then move it to inside of them. So actually don't need the image event listener. Yeah. I think we can delete it. That's cool. So what you do with would be the bitmap with. Okay. And then the play view height will be bitmap height. And then play view CTX draw image would be the bitmap. I don't need a console log. And fingers closed. This is. Fingers closed. This image will load. I have the greatest of faith in you. Still works. Yeah. Good to go. So we have avoided the image elements. We have avoided the fire reader API, which is good. So create image bitmap. I think the reason it got introduced is exactly for this reason they can decode an image, get the image data without having to jank the main thread. It's in Chrome. It's in Safari. It's in Firefox. It's in Firefox. But not supported in Edge or Safari. But they have it on their radar as far as I know. I'm not sure if they have it under consideration of their development, but they definitely know it's a thing. And they know it's a thing, a developer one. So as far as I know, in Chrome, they do this cool thing where the decoding of image, which is the most extensive part, they do it off thread, off the UI thread. So you can see those in a network. Start recording. Do this thing. Stop. And then you can see like less. Yeah, like much smaller thing. However, this here. The task at your render a foreground worker. Now that's a name. That's great. So that's basically. There you go. Image decode. So the image decode is happening in a worker that Chrome spun up, which means it's on a different thread. So it doesn't block the main thread. And that's what we want. That's good. So it's actually for bigger images. Yeah, I think as of like a year ago, it was decoding image on the context that called. So if you called it from UI thread, then it will decode it in the UI thread. If you call it from WebWalker thread, then it will decode in Walker thread. And I think Paul Lewis would have helped our library to make it easier for you so that you can load it fast. Of course he did. And I think I'm sure you can find it on our GitHub thing. But Chrome since then changed it so that like any image will be off the thread, which is amazing. So that was the one part of it. But then we haven't figured out the apply filter part. So the apply filter part is the one that still makes it super slow and not nice. So apply filter. We can delete this part. And this is when we get to use. Finally, after a good amount of time at work, we now have reached the point where the workers come into play. So what we're going to do is as we saw it, this part of going through each pixel and doing something was really expensive. Yeah. If you have like the other image is like what, 4,000 by 3,000 or something. So it's like 12 million pixels. That's going to take a while in JavaScript. But the lucky part is that this doesn't touch the DOM. This doesn't touch the UI. This doesn't have to do anything. It just needs to do the math. It just has to have the array, right? Right. Yeah. So we can load these to the worker thread. So the flasher of how worker works. More drawings. Love it. So again, there's two threads that we're dealing with. One is UI thread or main thread that you call it, which is where you deal with the DOM and UI. And then you spawn up a worker thread. Let me dive into the code. Yeah, go for it. I really like the style of annotating the code and kind of like picture of a code. So let me explain what's going to happen. So inside of your application, we are going to create a worker, which is a new worker. And then you pass a name of the JavaScript file that you want to execute in the worker thread. OK. But it's kind of like launching a international space station. Now you are starting something. We are launching international space stations. Something you can communicate with, right? So now go back to the worker thread side. If you want to use external library, it's kind of, I think it's similar to a service worker, right? Import script. Yes. It's exactly the same thing. It's the word you use to. So just to be sure, service worker, not supported in all browsers. Like Edge is just now working. I think they're close to logic. Who knows? Apple has announced they're working on it. Firefox has it. Chrome has it. Workers without the service bit. Every browser, even old Internet Explorer, has these. Yep. Just to be very clear about this. This is not like bleeding edge technology. This is 2001 technology, I think, or something. So, yeah. You create a worker JS with whatever that you want to do. Yeah. You launch it from your application side. And then now it lives in a different thread of the memory. How do you communicate those data, right? Like in, I'm sure we use satellite to send the data to, well, international space station in real life. I don't know what kind of technology they use. Laser. Do they use Internet? It's probably lasers. Anyway, so that communication is done by post message. Yeah. And on message event. So, from the application side, you call post message with, you know, the data you want to pass. And then on the worker side, you listen to on message event. Yeah. And I kind of like drew it like you do all the clicky thing while expensive stuff happens on the worker side. That sounds good. And once the worker is done, then they use the same thing. Post message to send the new data or new information that they calculated back to the main side. And now main side can listen to on message. And if you need to terminate it, you can terminate it. And I kind of like put it into like. That's horrible. We have this manmade glorious object, the international space station. And you want to throw it into a black hole? I could have come up with a good ending for a worker. Well, I mean, the author would have been just sending it into the earth atmosphere and let it burn. Yeah. That's sad. It's just a sad. You know what black hole, like new frontiers kind of approach to things. So let's go with that. So let's create a worker. Worker, new worker. And then I need to pass the file. So I need to make new file. What's the shift key for this? Every key is different here. Worker.js. So now I can reference this with. So that will basically just download the browser will go down on the file, create a new JavaScript thread, load that file in the thread, and then you have control over a separate thread just for yourself. Yep. So as I mentioned, worker takes a listen to on. Let's do the post message first. So I created the worker. I want to pass the data to worker so that working can deal with it. So worker.post is message M capitalized. Again, API so hard for me. So if you haven't used post message, it's just what it sounds like. It posts a message over to whatever you're post messaging to and post message can send JavaScript objects, but only objects. So you will lose as it's called the prototype chain. So if you have like a class instance, it will not arrive as a class instance on the other side, but as a symbol JavaScript object. But it's usually good enough if you have like just do a little like Jason style object. We like this is what I want to do. This is the my parameters and which is you probably want to do right now. So I created a post message in the image data. As I mentioned, this follow up needs to go to worker thread. So let's go to worker thread, worker file. And this one will come into play later, but let's create a message handler. How do you do the self dot on message? What do you usually do? I would usually just say, and I have to blame Jake for this because he basically said self is unnecessary. So I stopped using self. I would just say add event listener message. But if you want to use the on message, I would probably use self on message. Do I need to reference anything here? No, you can just. Oh, interesting. Yeah, I know, right? Because I think on the drawing, I still use the self dot on message. I think I just use whatever the Google developer site explained it to me. Or maybe HTML5 logs explained it to me. There's probably HTML5 logs out there for this. So message event will be fired. And let's see. So this, it's called D, data should be the data we passed. Yeah. And I want to see what this looks like actually. So again, console log, the greatest tool. And let's see. And that's also something that is good to know. If you want to work with workers, the debugging story around workers is actually fairly good. So console logs from your worker will just appear in your DevTools just as well. So you will be able to use this approach debugging. What is the role index 44? Something is not working. Oh, oh, oh, oh, because we are not using that image anymore. We're directly loading that. Correct. So this should be the size of preview now. Because we set the width and height there. So I can reference it with canvas. OK. So let's hope this works. Do the thing. There. Message event. And then inside of that, I have a data where data is exactly the representation of the image data we dealt with. Yeah. So inside of the worker, I get to access data.data.data. So this was a big image, but transferring it was surprisingly fast. Why? Oh, well, supposed to be this shouldn't be fast. True. Why was it fast? Either way. So the image data contains an array buffer. And array typed array buffer. And typed array buffers are JavaScript version of actual chunks of memory rather than abstract objects that you can pass around. And PostMesh has the ability to transfer those, which means instead of copying the entire image, it will actually transfer them. So no copying necessary. The main thing will lose access to this type of buffer, and the worker will get access to it. So basically, let's say you and I have a memory field. I have this image data here. And then I want to pass it to worker. Worker, if I don't on this line 46, if I don't have anything specified, then this is like a literally copied into your field. However, if I specify argument, which we'll get to, then it will basically says just to move the pointer. It moves ownership. Like you lose ownership, I get ownership and no copying needs to happen. Yeah. So that's good. And it's the weird API where like you have to pass an array. Yeah. It's a bit weird. And like specifying. So in this case, image data is the actual array dot buffer. Right. Because typed array buff, like there's array buffers, which are the chunks of memory. And then there's the typed arrays, which are views onto these buffers because you can interpret the same chunk of memory as like a series of floats or a series of eight bit integers. And we want to transfer the buffer, not the interpretation of the buffer, which is, I guess, the distinction, which it's a little bit weird, but maybe that's a good way to think about it. Yeah. This is like a little quirky bit that when you're dealing with a worker that you have to encounter, I guess, unfortunately. So inside of the worker, the image data is the one that we want to access. So let's say image data is the dot data. Right. And then we can basically access same thing. So let's do the same computation of making the face red inside of. The face red operation. Well, every warm filter. Not the face red filter. I like face red operation much better as an image. It seems like better branding to me. Okay. So I have a whole bunch of weird reference that I need to. So let's say with is inside of image data. With w is image data dot width. Let's make it more readable. That's good. Dot. And then data, the one that we are actually dealing with is image data. Okay. So now I need to tweak this a little bit. Ah, enter key. Backslash. W, height index. W, data index. All right. It's just data now. Yeah. All right. And now. So now we copy. So we send the buffer to the worker. The worker did the same thing as before. Like went through all the pixels did all the right manipulation. Now we just send it back. Yep. Okay. We need to send it back on a post message. So wait. So if you are in the other business, how do I send it to post message? Isn't it a global? Just post. I think in workers, it's just a global. So post message. Just go post message. Okay. It gets more complicated if you talk about service worker, because everybody can talk to the service worker, but the server can talk to all the open websites. So it's actually to define which window to talk to. And that's a whole different story. In this case, we have it nice and simple. We just call it post message. Yeah. It's weird for me to not like reference self, but I guess if Jake says self is not necessary, then it's not necessary. Okay. So supposedly we do all the things and then send the, use a post message to send the data that it was passed. Yeah. Because we manipulated inside of the data. Wait. Is D the data or is D the event? Because you're not sending back the event. Oh, that's true. So I have to do the image data. Yes. And also after the transfer bit again, right? Yes. Sorry. This is where you can tell that the post message API is really old because it feels pretty inconsistent with the rest of the web. But that is also, you know, the charm of the web kind of like, that's how it landed and that's what we got now. And it still works. Yep. So now sent it, but then we need to listen to it. So we can, this is part inside of doing it. Would you do it outside of this function? Yeah. You've done it so far. Why not? Guide us to the. Hi. What is that listener? Message. Let's see. Let's make it D. And if this pattern is repeating, then D.data should be image data. Sounds about right. Ah, we're copying pasting lines now. This is proper code reuse. And then put that data into the canvas. All right. I'm nervous. Let's hope this works. Yes. So it looks the same, but something a whole lot different just happened. Actually, yeah, let's do the performance check right away. So what is going on now is that we're doing the same thing as before, but all the expensive processing is happening in a different thread, meaning there shouldn't be any red bars if we do a performance analysis on this. Code, set it, done. How's that? Okay. That looks pretty short. And we can see the dedicated worker thread is what we are using. Yep. So a function called the worker.js happened in the dedicated worker thread. Okay. So previously, all of this, right, this part was clogged inside. You can mark regions with shift, by the way. Shift and click. Shift and click? What? Shift, click, and hold it. You can mark regions. And you can measure how white they are. Oh, TIL. Performance pro tip. So, previously, this whole chunk of yellow was living in here, which means it was blocking users' interaction. If they want to click on something or you want to do another JavaScript operation, it was just blocking. And now you put it done into, put it into worker thread. I mean, the ultimate test is now load the big image, right? Yep. And see if we have a six second frame or if the frame rate is going. Something better, right? Yeah. So let's do, record. Recording. Big image. There's a thread in there. That was also quicker. Yeah. Visually quicker. So here's an interesting, fun fact. Something I recently learned. If you look at the depth, at the bar graph at the top, the, you know, the little mountains thing. When something is striped, it means it's off main thread. So it means something is happening, but it's not blocking the main thread. It's good. And as you can see, there is no red bars because we are never blocking the main thread with this version. Because we're using decode image, get image bitmap, create image bitmap, and the worker. Yeah. So good. Yeah. So that's pretty much it, right? Nice. Do you want to do anything to other things? No. I mean, we are perfectly on time once again as on supercharged. It is common. Thank you so much for traveling all the way just for this. Your local? As Mirko promised, she is of course going to clean up the code or just give it to me. I'm going to put it on the GitHub repository, which I'm going to put in the video description once the video is up on YouTube. Thanks everybody for coming and talking to us in the chat. I've been super active there. I'm really, really happy to see that. As I already announced on Twitter, this is the last live stream for the 2017 season. It's time for a little Christmas break, but I'm going to be back. We're going to be back in 2018 with many more things I want to try. I hope you enjoyed this. I hope you learned something. If you have more questions, you can ask Mirko. Not me. Or me. It's okay. You can ask me too. Yeah, Twitter. Or they can ask the Chromium Dev Twitter. Also go to Chromium Dev. We are pretty responsive there. Yeah. It's actually we are the two active person who is watching that. You're mostly going to get replies from either Mirko or me if you tweeted Chromium Dev. If you want to stay up to date with supercharged live streams, micro tips, maybe even totally tuning tips. Who knows? Go to this channel so you get like little notifications when we put out a new video or we go live the next time. Thanks for watching. And I will see you all in 2018.