SURMA: It is Thursday. It is 2:30 PM, UTC. It is time for Supercharged. Hi, I'm Surma. MARIKO: Hi, I'm Mariko. SURMA: And we are going
to do some WebWorkers. Let's go. [THEME MUSIC] SURMA: So WebWorkers--
usually on Supercharged, we do more like leading-edge
technology, things that only work in Chrome
Canary with web platforms flag enabled. But today, with
WebWorkers, we're actually using something that
has been around for years. MARIKO: Yeah. SURMA: And many browsers-- I think even Explorer,
multiple versions, have support for WebWorkers. MARIKO: Pretty much. SURMA: 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. MARIKO: Thank you. SURMA: Before we
dive into code, I think we should make
sure that everybody-- I'm not sure everybody knows
what a WebWorker really is. MARIKO: Yes. SURMA: And even I'm
not sure if I know the right definition of it. Can you maybe bring
us all up to speed? MARIKO: Oh, OK. Cool. Sure. Should I do the picture? SURMA: If you want to. MARIKO: So how
would you describe WebWorker, if somebody asked
you online, what is WebWorker? SURMA: I would
basically say it's a 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. MARIKO: Right.
Right. So-- whoops. Yep, this one. I had that explanation
given to me. And I was like, what
do you mean thread? JavaScript is a single thread. SURMA: Exactly. And that's what already
confuses people, I think. MARIKO: Yeah. Yeah. So I discovered
WebWorker when I was trying to make the very
similar app that we're going to try to make today. And I wanted to
make it performant, and I discovered WebWorker. And I was like, what
does that even mean? It was really confusing. So I pictured it for you. I drew a picture. SURMA: You are known on
the Internet for drawing explanations of things. So I'm very happy
that Supercharged gets to enjoy these
drawings of yours as well. MARIKO: So imagine that
your browser is a planet-- Earth, something. You might know when
the garbage collection is, you know, the
garbage day schedule with garbage collection. You know all the elements on the
planet, because HTML elements up there. And the WebWorker,
you can think of it something like a
International Space Station. It's something that you create
from the browser, the planet browser. You launch it-- SURMA: I like planet browser. MARIKO: --out of the world. It's outside of
the planet browser. But then, from
planet browser, you send the data out 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 WebWorker-- SURMA: That makes
a lot of sense. MARIKO: --it does not have
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. SURMA: True. And that's what we're
going to use today. MARIKO: Yes. SURMA: 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 Supercharged on Twitter,
or my mentions on Twitter. And I'll try to
forward them to Mariko, because she's the expert
on 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? MARIKO: What? Coconut? I'm sorry? SURMA: Jake said
in the chat that I should say something
about coconuts to prove that this is live. MARIKO: Oh yeah. By the way, for somebody
who doesn't know Jake, he's our colleague
who is literally sitting at the wall behind us. SURMA: He did the livestream
with me two months ago, three months ago,
about ServiceWorker. Who would have thought? MARIKO: OK. So as I explained, in
order to utilize WebWorker, you kind of have to have a
lot of JavaScript to do-- like 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 what if we-- so I know Matt did last
Supercharged an image processing thing and WebGL. SURMA: Yeah, we did WebGL. MARIKO: 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 our
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-- [LAUGHS] SURMA: The bits thing. MARIKO: That thing, yeah. That, the thing, the
pixel thing that you-- SURMA: 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. MARIKO: So here's the
very simple diagram of what's in my head. SURMA: OK, this is what
we're going to build. MARIKO: Yeah. 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
the screen, it does something. Let's say, it's kind of like
an Instagram filter, right? SURMA: Yeah. MARIKO: You know, let's make
it like a black and white, or like, you know, warm, cool-- SURMA: Any kind of
image processing, MARIKO: Yeah. SURMA: [INAUDIBLE]
image processing. MARIKO: And then display
it on the screen. SURMA: OK. MARIKO: Because I suspect
that doing those filter things involves a lot of computation. SURMA: Yeah. MARIKO: And maybe
it's a good example to put it into WebWorkers. So let's get into first making
that application, before even we talk about WebWorker. SURMA: Yeah, let's go for it. MARIKO: All right. So I have index.html. And I start a simple server
that is serving that file. SURMA: OK, cool. MARIKO: Let's just
see 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. SURMA: And we're done. MARIKO: [LAUGHS] SURMA: See you next time. MARIKO: Supercharged. SURMA: Oh, you're even on brand. That's so good. MARIKO: Emoji. And then-- SURMA: No, it's one word. MARIKO: Thank you, very
much for reminding me. So as I mentioned, I need to
have Input button, so input. SURMA: We have the first
question for you on the chat. What do you use to
draw your diagrams? MARIKO: I use iPad. SURMA: There you go. MARIKO: And Apple Pencil. SURMA: OK. MARIKO: Do they care
about the app that I use? There's a bunch of apps
that I can recommend later if you want to do it. Yeah. SURMA: Speaking of, follow
Mariko on Twitter as well. MARIKO: Yep. SURMA: If you want to
have more drawings, that's the place to go. We have the link
in the description. MARIKO: Cool. So when you have an
input for element, you can specify what
kind of input it is. And in this case, we're
going to use file. And then, when you're
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 image. Like, you don't want a
user to accidentally load. SURMA: Like a JSON file or HTML. MARIKO: JSON file or something. It's just like
[INAUDIBLE] everywhere. Let's do that. So image. And then let's say star, so that
in PNG, JPEG, bitmap, anything, it will accept it. And just have an input. SURMA: Cool. Also it uses the MIME type,
not the file extension. MARIKO: Right. SURMA: OK. MARIKO: ID, ah, input. SURMA: Because people,
someone brought up that we are missing some
meta tags in the header. This is a good opportunity
to mention this is not production ready code. This is only supposed to work
on Mariko's screen just now. Its more about the
concepts that 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. PR is welcome. MARIKO: That's good-- PR for PR. SURMA: Exactly. MARIKO: So choose file
or something, right? So if I had that, I
should have for input. And then let's
leave out this file. And then I have file input. So right now, its very small. So make it bigger. SURMA: Yeah. MARIKO: If I click it, the
file dialogue opens up. And then I can select the
image and then open it. SURMA: And then nothing happens. MARIKO: But right
now, nothing happens. SURMA: Why would it? You haven't written anything. MARIKO: Nothing written yet. 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-- SURMA: No. I am 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. MARIKO: So as you can
see, I'm a visual person. SURMA: You don't say, the
person who draws on Twitter? MARIKO: I mean I'm not, no way,
like a designer or anything. But I'm definitely drawn
to visual, shiny things. So let me just style
that quick, first. SURMA: Yeah, go for it. MARIKO: So I'm just going
to style it bluntly, and you can take questions. SURMA: I guess I can actually-- MARIKO: First of all, I
have a question for you. SURMA: Oh, a question for me? MARIKO: I want to have a
ID selection on my CSS. SURMA: Yes. MARIKO: This keyboard does
not seem to have a slash. SURMA: So you are actually
usually in the New York office. MARIKO: Yes. SURMA: Now 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 a UK keyboard. Shift+3 is the combination for-- MARIKO: Wait. Oh, that was caps lock. Oh. SURMA: There we go. MARIKO: I'm sure I'll ask you. SURMA: What is it? On the American keyboard,
you have a separate key for the hashtag, right? MARIKO: Well, where the British
pound sign is, it is already listed as a pound. SURMA: OK. I see. MARIKO: I mean, pound, but like
pound meaning like a hashtag. SURMA: Not our currency. Words are confusing. All right, keep styling. MARIKO: Styling-- yep. SURMA: I wanted to quickly
answer Tim's question from the chat, on the
video as well, because it is interesting. We have been talking about
modules on the Chrome Dev. 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 has actually implemented it. That's something that
I guess [INAUDIBLE] have on the road map. 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. MARIKO: I, P, X. SURMA: So we have
some more colors. MARIKO: Yes. SURMA: This looks-- MARIKO: Let's make
it font size bigger. SURMA: I never use the EM type. Maybe I should use it more. MARIKO: Yeah, that looks good. So what I did was I've hidden
a default Input button. And then I made the label
part as a clickable. SURMA: Ah, that's
a good old trick. MARIKO: Yeah. SURMA: You have to be careful
with accessibility on this one. MARIKO: So I prepared for this. I care about this thing. I do front end development. SURMA: You go and explain this. MARIKO: So right
now, if I tab it, I can't get to the
input element which I should be able to because
it is an input element. SURMA: Yeah. MARIKO: But the one that
is focusing input element is basically [INAUDIBLE]
overflow here. And that's completely hidden. And it's just the
display is taking over SURMA: Practically invisible. MARIKO: Right. So I need to put a
focus to this element. So, again-- SURMA: Oh, so when the
input element is focused, you're going to change
the style of the label. MARIKO: Yes. SURMA: Tricky. Because what a lot of people
do is actually display none in the input field. And that is very
bad flexibility, because then it becomes
non-focusable 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-- MARIKO: So I kind of cheated. Because I couldn't remember
the order of pixel order, or style, or anything. But let's see if this works. So if I tab it, yes. SURMA: Nice. MARIKO: And then tab out. So now, I can select it. So now I can see
this is selected. Enter, and then file opens. SURMA: Cool. MARIKO: And then select it. So cool. Now we have something
to start with. And that's pretty much
the only UI element we will have on
this, so we're done. SURMA: Sounds good. Now we have to do something
with the image, right? MARIKO: Yeah, let me
just change the color. This is not fun. Color-- let's say F3, F3, F3. SURMA: You're just making
those colors up, aren't you? MARIKO: Yeah. Blue is not cool. Teal? Yeah. SURMA: Let's go with that. MARIKO: OK, so now we get
into the 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. SURMA: Yeah, that's
how we roll here. No worries about that. MARIKO: [INAUDIBLE]. So let's do the JavaScript part. SURMA: Look at
that auto-complete. MARIKO: Don't you think my
Sublime setting is supurb. SURMA: We haven't had Sublime
on this stream in a long time. Have you heard of
[INAUDIBLE] code? MARIKO: Yes. SURMA: 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 Notepad++, it all
works for web development. So don't ever feel
discriminated if you use a different editor from what
you see other people using. MARIKO: Yep, so while
Surma is putting the disclaimer about the
editor, I just put the-- SURMA: I like the shoutout
to the old jQuery syntax. MARIKO: Oh. So is what I do. So whenever I do reference
to the DOM element or HTML element that is already
existing in the screen, even though I don't use
jQuery, I just put dollar sign. So that makes a
mental note of like-- SURMA: It's a signifier.
I like it. MARIKO: You know, I can see
which element object 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 I add [INAUDIBLE]. So change event
is fired whenever user selects different files. SURMA: Yeah. MARIKO: So another apology. I'm going to console log
the hell out of this code, because that's how I code. SURMA: That's how the
professionals debug. I think that's perfectly fair. MARIKO: So let's see what kind
of event data that we get. So let's tab, select picture. Oh, oh, oh, I need to to
do the dev tool, don't I? Inspect, console--
something is wrong. SURMA: Oh yeah. MARIKO: Oh, oh, oh. SURMA: Capitalization of that
function call is always weird. MARIKO: Consistency is something
that we don't have on the web. All right. SURMA: So we've got an event. MARIKO: Evenut
usually-- usually, it's in the target where you
want the data to be, right? SURMA: Yeah. MARIKO: And I just
happen to know that if it's file in the
target, there will be files. SURMA: Ah, so we actually get-- MARIKO: And then that's where
all of that information-- SURMA: --and that's
an actual file type, so something you can read. MARIKO: Yep, so the name of
the file, metadata of things. SURMA: That's actually
pretty interesting because you selecting
a file, it's implicitly granting you,
as the website, permission to read that file. So we're already done. We can now read this
fine and work on it, which is what we want. So that's cool. MARIKO: So let's say the
file that we want to access will be const file equal
e.target.files, and then the first one in there. Now we have access to
all the information, but we have to actually
load it in the browser. SURMA: Yes. MARIKO: We only
got the metadata. SURMA: Yeah, it's like an object
representing the file, not the actual contents. MARIKO: [INAUDIBLE]
hasn't figured that out. So in order to do that,
we make a file reader. SURMA: Oh, I have touched on the
file reader API, not on stream, but I have used it before. It's not the nicest API to use,
but I guess you'll see now. MARIKO: So file
reader, as it suggests, it just reads the file. And it comes with a
lot of methods to read. So one way to read a
file is read as data URL, which basically returns-- [INAUDIBLE] if it's basic 64
representation of the file. So I created the file
reader here on the line 30. SURMA: I guess
interesting to note that it's like--
most of you probably have seen data URLs
somewhere, like when you in-line 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. MARIKO: Yep. And then, once
you read the file, you have to do something
once the reading is done. Because it is done-- what do you call it? Asynchronously? SURMA: Yeah. MARIKO: You basically have
to listen to onLoad event. SURMA: Oh, OK, yeah. MARIKO: So I would add a
file reader.eventlistener, and then load. SURMA: So somebody asked,
why are you using const? Is it necessary? MARIKO: That's a good question. I don't know. I started using const. I started basically
ditch every var and-- SURMA: Exactly. MARIKO: --replaced
it with constant. SURMA: I think, on
some stream previously, we talked about this. There used to be everything
in JavaScript used to be var. And now there is let
and const with ES 2015. 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 they're block scoped, rather
than function scoped, which in JavaScript is
the default and very confusing at times. MARIKO: Yep. So I just created a file reader. Read it as a data URL. Pass the file. In the file reader, 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, within the target, I get the result here, which
is a B64 representation of the image that we loaded. SURMA: It's beautiful. I can practically see the image. MARIKO: So let's say
const image data. Well, that's going to
be confusing so EMB is E.target.result, right? So now, we need to somehow
put this data into the browser so that browser shows
the image, right? SURMA: Yes. MARIKO: An easier way to do
it is making an image object. So again, image, new image. Ooh, ooh, ooh. I just [INAUDIBLE]
deleted the semicolon. SURMA: [LAUGHS] MARIKO: You made a comment
recently about my code. SURMA: I did. I personally am a big
proponent of using semi-colons in JavaScript. Mariko's not. I disapprove. MARIKO: I don't have any
strong philosophical belief or anything. I just worked in a company
for two years that-- SURMA: And I think
that's the thing. It's mostly an acquired taste. The way you start
coding is the way you're going to keep coding. MARIKO: I mean, if
somebody makes me like, you know, you should-- let's say
like our team decides everybody should write semicolons. I would happily adopt it. But there's nothing,
no mandate here. SURMA: I mean, we have a
Google eslint configuration, which will demand semicolons. But, you know, I have eslint
now on most of my projects. But for this, Supercharged
is a production-ready code, so who cares? MARIKO: Yep. So I created an image
object on line 31. And then now, I assign the B64
representation of the-- oh, let's say this-- Base 64. 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
child image. And let's see if this works. Click, clickity, click. Yay! SURMA: We just loaded an
image with a file selector. MARIKO: Yeah. SURMA: That's pretty damn cool. MARIKO: Yep. For the reason that
comes in later, I'm just going to wrap
this in div so that the-- SURMA: You can always divs. MARIKO: Again, I just
need to kind of, like-- I'm not a designer, but I need
to style something, you know? OK, Oops. All right. So now that we have
a user select image, data image is globbed from the
memory, we put it into browser. Let's put it in so we can
apply the filter, as originally planned, right? SURMA: Yes. So I guess you can't do
that on the image element, but you need a canvas. MARIKO: Yes. So image element is
great, but it doesn't have a finer way of tweaking things. I know you can use a
CSS to put a filter. SURMA: But that's
not the point today. MARIKO: But you know, yeah. That is a very specified thing. That's not the point. That is like you're offloading
a mass problem to CSS. We want to do the
math on the JavaScript so that we can use WebWorker. So let's make a canvas
where all of this happens. SURMA: We just
published an article about how expensive a blur is. And 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. MARIKO: I did. It was a wonderful article. SURMA: Yeah. And the point is,
today, we're going to use a WebWorker eventually
to offload heavy work. But that article basically
explains why you blur. It's so computationally
intensive, even though it is
a simple effect in terms of what it looks like. MARIKO: Get context 2D. So I suppose I should explain
this part if somebody has not done canvas work. So Canvas, much like
any other HTML element, you just create a
canvas tile, right? SURMA: An element, yeah. MARIKO: And then you can
reference it by ID, or class, or however you would do. SURMA: You typo-ed the ID. MARIKO: Oops. What? SURMA: The V is missing. MARIKO: Ooh, V-U. SURMA: And the I. There you go. MARIKO: So that's
what's happening here, a dollar sign preview. However, in order to do a lot
of computational work on Canvas, you have to define the language
that they are speaking. So going with a
planet explanation, let's say you decided to-- I don't know, you
are a master creator. So you decided to create
this planet, right? SURMA: Yeah, as you're
known to do on Friday. MARIKO: You decided to speak. I'm going to speak this one
language, which is WebGL. SURMA: Yes, which was
[INAUDIBLE] last time. MARIKO: Yep. So you would say, the WebGL uses
a specific thing called shader. And then that's how you
communicate with this canvas planet. In 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 are 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. SURMA: That's the
actual manipulation API. MARIKO: Yep. So the canvas-- you can maybe
set the width and height of the canvas. And that's about it. SURMA: That's pretty much it. Like if you do the
WebGL canvas, you get all the functions to load
triangles to the [INAUDIBLE],, to upload textures. And in this case,
you get functions to draw lines, draw
circles, whatever you want to do as a 2D operation. MARIKO: Yep. So instead of loading an
image as a child element, now I put a image into the
canvas and call the method that canvas has,
which is drawImage, which basically takes
an image element and puts it into the canvas. So let's do the thing
and see if it shows up. Oops. Hello. Oh, OK. When you're drawing
the image, you're first argument is the image
object that you're putting to. And then you need
to give the location where you want to draw. SURMA: I wish that was just
half-sensible defaults. But sadly, this
function does not. MARIKO: So I want to
draw it full size, so I would say that the top left
corner has to be zero, zero, X, Y. So zero and zero, and
hopefully, this should draw a picture into canvas. Yay. SURMA: I mean, part of the
image is missing, but you know, that's good enough. MARIKO: 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 created canvas. SURMA: And we didn't div it. MARIKO: And default size
for canvas, I think, it's 200 pixel by 400. SURMA: I thought
it was 300 x 150. MARIKO: Oh, maybe. SURMA: Like an iPhone. MARIKO: I only remember 1 x 2. SURMA: Yeah, it might be true. MARIKO: So we just
need to set the size. So in here, I would say, preview
with the name of the canvas. So preview.width-- SURMA: Oh, so you're
going to resize the canvas before drawing the image. MARIKO: Yep. SURMA: Which makes
a lot of sense. Because a lot of people
apparently are very interested [INAUDIBLE]. It is real, it's
just not switched on. And why would it be? It would just be dangerous. MARIKO: Solving what? SURMA: The [INAUDIBLE]. MARIKO: Oh, yeah. Yeah, yeah, yeah. SURMA: It is real,
I'll tell you that. MARIKO: There we go! So now-- SURMA: Hurrah! MARIKO: --it shows up
on the great screen. SURMA: All right. MARIKO: Let's just make, maybe-- I'm going to do maybe a bad
technique of putting BR. SURMA: [GASPS] I'm disgusted. MARIKO: Because all I
care is how it looks. SURMA: And that's how
bad websites are born. Welcome to Supercharged. MARIKO: Does that even work? Yes. SURMA: Of course, it does. MARIKO: Later, if
I was pushing this, I will clean it up with nice
[INAUDIBLE] and everything in TechWiz Designer,
but for now-- SURMA: Right. MARIKO: What do I need to do? Oh, yes. So now that the
data is in Canvas, we can also get the
data out of Canvas. SURMA: We can read
back the pixels. MARIKO: Yes. So let's just
switch up this thing and make it like a function. So apply filter as a function. And then we will have
a separate function. SURMA: I mean, I was about to
say it's a function that GL's going to write. It's not a function yet. MARIKO: Right. SURMA: Now it is. MARIKO: Fun-- oh, I can't type-- function. SURMA: 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 never-- MARIKO: See, this is the thing. It's not showing up. But the enter key is so
small on the British thing. SURMA: It's bigger
than on the-- oh, I guess it's taller
but narrower. MARIKO: Yes, yes. SURMA: --while on the American,
it's like wider, but-- and whatever you're used
to, you will totally mess up once you are
on the other keyboard. It's horrible. When I go to America, I
just can't type anymore. And for you it's basically
the same just now. MARIKO: Yep. So canvas has this very
handy method called getImageData and putImageData. Image SURMA: You wrote "with" here. I think-- MARIKO: Ooh. SURMA: How did this work? Just by coincidence? Probably. [LAUGHS] Love it. MARIKO: Maybe, yeah. All right. All right, apply filter. In order to apply the filter-- SURMA: Thanks for the chat. MARIKO: 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're
only interacting with the HTML element. We don't have that
data element, right? So in order to do those,
Canvas has a method called getImageData and putImageData. 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 a context, right? Context.call getImageData. And then on the
parameter, you can specify where that
should start and how big. SURMA: So you can
get a subrectangle of the entire image
as [INAUDIBLE].. MARIKO: So you have
four arguments. And then you get data. And then make it pretty. And then you pass that data
into putImageData method. And then put it back
into the screen. SURMA: OK. Cool. MARIKO: So that's what
we're going to do now. SURMA: So basically,
you're going to take the image out, do some
crossing, and put it back in. And that's how you do effects. MARIKO: So let's see
what that data that we've been talking about looks like. So say I already have a
context, so preview context dot getImageData, and zero, zero. And it would be image dot width. SURMA: Oh, we were using that. That makes sense. MARIKO: [INAUDIBLE]. Yep. SURMA: Yep. MARIKO: And let's
see [INAUDIBLE].. SURMA: Cool. So what exactly is-- like, what is the image data? Is it like a special type? Or is it just an array? MARIKO: So image data
is a special, I guess-- oops. SURMA: It's an error. MARIKO: Image data
is not a function. SURMA: Oh, I think the I
needs to be capitalized. MARIKO: Oh, yeah. So it's a special-- what do you call it? Object or data type? SURMA: A type. It's a type. OK. MARIKO: So you can see-- SURMA: Ah. So-- OK, keep going. MARIKO: Yep. They have three data in
there, width and height. And then inside of
that, data is an array. And the array-- SURMA: [INAUDIBLE] typed array. MARIKO: Typed array, yep. Array is a-- SURMA: This is the feature
I love DevTool to make. Like, how many-- 360,0000 element array, and you
can inspect every single one of those cells. MARIKO: Yep. So you can see, here is the data
of a whole bunch of numbers. SURMA: OK, but those are
just numbers, not really-- what do those numbers represent? MARIKO: So, yes. [LAUGHTER] This represents the image
that's on screen here. SURMA: Yes. MARIKO: It's loaded
on the canvas, but it is arranged
in a certain way. And it's a one-dimensional
whole bunch of numbers. And the way I think about it
is it comes in the set of four. So from zero to
three is the data you need to represent one pixel. SURMA: Ah, OK. MARIKO: And you might have
guessed it, it's RGB and alpha. SURMA: That's why every
fourth [INAUDIBLE] just now is 255,
because we don't have any transparency going on. MARIKO: Yes. SURMA: OK, 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 they can probably
handle that. MARIKO: One thing that
changed from the CSS is that, in the
CSS, if you do LGBA to set the color, the
A, the last value, it would be zero to 1. But in the Canvas case,
it will be zero to 255. SURMA: Oh, OK. MARIKO: Yep. Because the thing that
we are using is 255. So you may ask-- but it's flat, how do you know
where in position that pixel is located? SURMA: That sounds like math. MARIKO: So when you are
writing a letter to somebody-- and 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 letter, you would get this graph paper. So each square is
for one letter, righ? SURMA: Yeah. SURMA: So in my
head, I'm thinking in the one-dimensional
way of, hi, Surma. It's like one-dimensional. I wouldn't think
about, like, here is going to be a line
break or anything, right? SURMA: That makes sense. So basically-- MARIKO: And then,
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 the next row. SURMA: I see. MARIKO: And then fill
in what's in my head as one-dimensional data, right? It's the same thing. So from here, the first
four is the top left corner. And the next one
is the first lower, but the second from the left. SURMA: 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, we go back to the first
pixel, the next line. MARIKO: Yep. SURMA: All right. That makes sense. MARIKO: So because
we have the width and height and a whole bunch of
data, we can deconstruct this. SURMA: OK, cool. MARIKO: And we know
where exactly which number is for which pixel
over which color channel. SURMA: And now we can
probably jumble around with those numbers and make
the image look different. MARIKO: Yep. So let's see, in
order to do this-- oh, this is a very tedious part. So as I mentioned, we
were just explaining this. We have to do this
in code, right? SURMA: I'm smelling For loops. MARIKO: Yes. So for loops-- SURMA: So for everyone who has
joined just a couple of minutes late than we started, welcome. This is Mariko. MARIKO: Hello. SURMA: I'm Surma. I mean, we said we were
going to do WebWorkers. We haven't even touched
the WebWorkers 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. Mariko's coding, 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 have 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 WebWorkers
has to do with it. MARIKO: Yeah. SURMA: So OK, we're
doing the classical-- MARIKO: Yeah, if you've
dealt with Canvas, this is engraved into your heart
that you're like, oh, yeah, yeah, you don't do those things. But I will explain what's
happening in a minute. There should be parentheses. And there should be D. SURMA: Are you sure? Oh, index. MARIKO: Oops. SURMA: Yeah, that's
probably For, right? Should there also be a
times and not a plus? MARIKO: Yes. [INAUDIBLE] processing. SURMA: We have done this before. I mean, not us, but I have
done pixels reversion on images before. MARIKO: Right. So what's happening is,
after For loop is X, so going through this direction. And end of For loop is Y, so
going through this direction. SURMA: Yes. MARIKO: So in combination
of those, you get to do-- SURMA: Every pixel. MARIKO: Every pixel. However, every pixel,
remember, has a four values. So index has to be padded
with four, every time. SURMA: Yes, so if we
increase the index by one, we have to jump four fields. And that's why it's times four. MARIKO: Yeah. SURMA: OK. MARIKO: Can I show
off my drawing? Because I'm really proud of it. SURMA: I would love for you
to show off your drawings. MARIKO: Here is the
visual explanation of what I just said, right? SURMA: Right. MARIKO: So the outer
loop is the green. Oh, in this case, I
actually did Y. Sorry. SURMA: It doesn't
matter, really. MARIKO: 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 3. SURMA: Yes, that makes sense. MARIKO: And you just do
something, cool thing happen, once you have access
to those things. SURMA: We're going to do
the cool thing, as well. Don't you worry. MARIKO: So let's see. Let's say changing
opacity, maybe? SURMA: Yeah, that sounds good. MARIKO: That's an easy one. SURMA: That sounds easy enough. MARIKO: 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. SURMA: OK, so now we have
changed the fourth value in each pixel pack,
the A value 247, which is basically 50% capacity. And it's plus three. Because as always, in
programming, we start at zero. So zero is the first pixel. And so plus 3 is
the fourth value. MARIKO: So I just changed all of
the value which is in the image data dot data, right? And then I put dot data
back here on this line. So hopefully, this picture
will come as slightly opaque. Yay. SURMA: Nice. We just have done
image processing. MARIKO: Yep. SURMA: We're done. MARIKO: [LAUGHS] We can
totally do the thing where-- let's see, with
changing the thing, I think Matt did a warm
filter or something. SURMA: Yeah, he had a
warm filter in the end. MARIKO: R is the red value. So I think what he
did was increase the red value a
little bit to make it like a more slightly warm. SURMA: Yeah, I think
he had a factor. And he would add to the red
and subtract from the blue, depending on how high the
warmth value was supposed to be. MARIKO: OK. Well, let's just do
the simple thing of red is where the first one. So index, right? SURMA: Basically, we're going
to make Jake's face more red, which is what he looks like
once he has seen the sun. MARIKO: True. Oh, that's a good one. And then times one-- SURMA: Literally burnt. MARIKO: 1.1 or
something-- well, 1.2. Let's see. Right? SURMA: Because the
first is the red value, you're increasing the red value. MARIKO: Yep. SURMA: And interesting fun fact. Because the image data dot data
is a clamped [INAUDIBLE] data array, if we go above
255 it will automatically stick to 255. MARIKO: Yeah, I
love this feature. I love it. SURMA: And the same with zero. You can't go negative with
a clamped [INAUDIBLE] data array, which makes it super
handy for this kind of image data. MARIKO: So choose Jake's image. SURMA: Definitely more red. MARIKO: Definitely more red. You seem a nicely tanned color. SURMA: I never do in
real life, though. MARIKO: So that's good. SURMA: Yes. MARIKO: And this seems
to be working fine. But you know, in real life,
the photo we take on the phone is much, much bigger. SURMA: That's true. I mean this picture,
I think, we saw in [INAUDIBLE] was 300 x 300. MARIKO: Yeah. Nobody takes those photos. SURMA: No, nobody does. MARIKO: And I want to keep-- I don't want to resize it
to make it fast, right? SURMA: Yeah. MARIKO: I want to keep
the original size. SURMA: Of course. MARIKO: I basically
want to [INAUDIBLE] SURMA: You don't want
to lose quality just because you did some touch-ups. MARIKO: Yeah. So I have a big
file, the cat JPEG. And once I open it,
visibly, this is very slow. SURMA: Well, nothing happened. Oh, it just-- oh, so
like it didn't not work, it just took that long to
draw and process the image. OK. MARIKO: Yep. SURMA: 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. MARIKO: Yeah. So let's investigate. So you may need to help
me here because I'm not an expert on the thing. But as I've heard,
you just hit record. SURMA: That is correct. MARIKO: And then do something
that you want to record. And then wait for it to happen. SURMA: OK, so DevTools
is still working. It still hasn't
appeared on screen. There it is. MARIKO: Stop it. SURMA: And let's see
what DevTools says. DevTools says there's 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 inputs, 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. MARIKO: Yeah. SURMA: 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 than 16 milliseconds. This was six seconds. That's too much, Mariko. MARIKO: Yeah. And to be fair, I doubt it will
go down to 60 frames per second when it's 2D canvas. SURMA: No, the image
is just that big. There's not much
we can do about it. MARIKO: The image
is just that big. But we can minimize
it so that the user can have a brake point so that
they can interact with the UI. SURMA: Oh, OK. MARIKO: So it's like the
perception of the speed is faster. SURMA: OK. MARIKO: You know, fake
it until you make it. SURMA: That's right. That's what we call performance. MARIKO: Yes. So let's do this. The first thing that
is very blocking-- and it would help me
if you can point it-- the loading the image part. SURMA: I mean, there's
the load event. Oh, that's when it's
already loaded, right? MARIKO: Yeah. Function call, add
event listener. SURMA: It's [INAUDIBLE] quiet. What are you looking for? MARIKO: The image loading part. I suspect this
chunk is where we-- yep, file reader. We were reading the file. So I happened to know the-- it's not that new, but
it's newer than WebWorker. SURMA: True. I mean, pretty much anything is
newer than WebWorker, almost. MARIKO: [LAUGHS]
So do you know what it is that I'm going to use? SURMA: Is it create
image bitmap? MARIKO: Yes. SURMA: Yes, it is! MARIKO: Yay. So there are the-- what do you call it? API? SURMA: Yes. MARIKO: Call create
image bitmap, which allow you to pass a file
data and magically creates an image for you. SURMA: So this will allow
us also to not only make the image decoding
be a janky process, but it will also avoid
the file reader API. MARIKO: Yep. So I do not need file
reader API anymore. SURMA: That is so much better. MARIKO: I don't need
to listen to the thing. I don't need to
listen to the image-- oh, I still do, maybe. SURMA: Yeah, you still want
to know when the image-- MARIKO: Right, but I can
delete the file reader. SURMA: And that's good. MARIKO: For sure. Create image bitmap
is a promise based. SURMA: Nice. I'm a big fan of promises. MARIKO: Once things are done
you call it withstand and then-- SURMA: Or an
[INAUDIBLE] function. Or we can use then, it's fine. It's completely
valid, just saying. MARIKO: Do you want to do it? SURMA: No, no, no. This is your code. If I would take over
right now, the first thing I would have to do is add
semicolons to every line. So we're not doing that. You keep coding. MARIKO: 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. You directly go to the camera. So let's just
[INAUDIBLE] like this. I don't even know what it was. SURMA: OK, yeah. So basically, you want to
just see what kind of type you get back. MARIKO: Yeah, so let's
just do the small one before we go into the thing. OK, so [INAUDIBLE] bitmap. SURMA: Just as height and width. MARIKO: Yes. SURMA: Done. MARIKO: And then I remember
this API only exposes width and height to developers. SURMA: As properties? MARIKO: Right.
Yeah. SURMA: But they can be methods? MARIKO: Yes, 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. SURMA: OK. MARIKO: So let's see. I take this code here and then
move it to the inside of that. SURMA: So you actually don't
need the image event listener here. MARIKO: Yeah, I think
we can delete it. SURMA: That's cool. MARIKO: So preview width
would be the bitmap width. And then the preview height
will be bitmap height. And then preview ctx draw
image would be the bitmap. I don't need a console log. And fingers crossed,
this image will load. SURMA: I have the
greatest of faith in you. MARIKO: Uh-huh. Uh-huh. SURMA: Still works. You're good to go. MARIKO: Yep. SURMA: All right. So we now have avoided
the image element. We have avoided the file
reader API, which is good. So create image bitmap-- I think the reason it
got introduced is exactly for this reason. It can decode an image,
get the image data, without having to
jank the main thread. It's in Chrome. It's in Safari? MARIKO: It's in Firefox. SURMA: It's in Firefox. MARIKO: But not supported
in Edge or Safari. SURMA: But they have it on
their radar, as far as I know. I'm not sure if they have
it under consideration or in development, but they
definitely know it's a thing. And they know it's a
thing at developer one. MARIKO: Then as far
as I know, in Chrome, they do this cool thing
where the decoding document, which is the most
extensive part, they do it off thread,
off the UI thread. So you can see
those in a network. Start recoding. Do this thing. Stop. And then you can see less-- SURMA: [INAUDIBLE]? MARIKO: Yeah, like
much smaller thing. However, this here-- SURMA: The task [INAUDIBLE]
render a foreground worker. Now that's a name that's great. So that's basically-- MARIKO: There you
go, image decode. SURMA: 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. MARIKO: Yeah. SURMA: So that's good,
especially for bigger images. MARIKO: Yeah. I think, as of like a year
ago, it was decoding images on the context dot code. So if you coded from
UI thread, then it will decode it in the UI thread. SURMA: Yeah. MARIKO: If you coded
from WebWorker thread, then it will recode
it in Worker thread. And I think Paul Lewis
wrote a helper library to make it easier for you so
that you can load it fast. And I'm sure you can find
it on our GitHub thing. But Chrome, since
then, changed it so that any image will be off
the thread, which is amazing. So that was one part
of it, but then we haven't figured out
the apply filter part. SURMA: So the apply
filter part is the one that still makes
it super slow and not nice. MARIKO: Yep. So apply filter. We can delete this part. And this is when we
get to use WebWorker. SURMA: Finally! After a good amount
of set-up work, we now have reached
the point where the workers come into play. MARIKO: So what we've got
to do is, as we saw it, this part of going through
each pixel and doing something was really expensive. SURMA: Yeah, if you have
the other images, like what? 4,000 x 3,000 or something? So it's like 12 million pixels. That's going to take
a while in JavaScript. MARIKO: 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. SURMA: It just has to
have the array, right? MARIKO: Right. SURMA: Yeah. MARIKO: So we can load
these to the Worker thread. So referesher of
how Worker works. SURMA: More drawings. I love it. MARIKO: So again,
there's the two threads that we're dealing with. One is a 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 WebWorker thread. Let me go dive into the code. SURMA: Yeah, go for it. MARIKO: I really like the style
of annotating the code and kind of like picture of the 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 WebWorker. And then you pass a name
of the JavaScript file that you want to execute
in the Worker thread. That is kind of like launching
an International Space Station. Now, you are starting-- SURMA: We are launching
International Space Stations! MARIKO: --something you can
communicate with, right? So now, go back to the
Worker thread side. If you want to use
external library, I think it's similar to
ServiceWorker, right? Import scripts-- SURMA: Yes, it's
exactly the same thing. MARIKO: --is the word you use. SURMA: Just to be sure,
ServiceWorker is not supported in all browsers. Like edge is just now working-- I think they closed
the logic on us. Apple has announced
they're working it. Firefox has it. Chrome has it. Workers, without
the service bit, every browser, even old
Internet Explorer, has these. MARIKO: Yep. SURMA: Just to be
very clear about this, this is not like
leading edge technology. This is like 2001 technology,
I think, or something. MARIKO: So yeah. You create a worker JS with
whatever that you want to do. 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? I'm sure we use
satellite to send the data to our International
Space Station in real life. I don't know what kind
of technology they use. SURMA: Lasers. MARIKO: Do they use Internet? SURMA: It's probably lasers. MARIKO: Anyway, so
that communication is done by post message
and all message event. So from the application
side, you call post message with the data you want to pass. And then on the worker side,
you listen to on message event. And I kind of drew
it like you do, all the clicky thing while
expensive stuff happens on the worker side. SURMA: That sounds good. MARIKO: And once the
worker is done, then they use the same thing--
post message to send the new data or new information
that they [INAUDIBLE] back to the main side. And now main side can
listen to our message. And if you need to terminate
it, you can terminate it. And I kind of like put
it into guiding them to-- SURMA: That's horrible. We have this man-made,
glorious object-- the International Space Station. And you want to throw
it into a black hole. MARIKO: I couldn't come up with
a good ending for WebWorker. SURMA: Well, I mean the other
thing would have been just send it into the Earth's
atmosphere and let it burn. MARIKO: Yeah, that's sad. SURMA: It's just a satellite. MARIKO: A black hole is
a little more romantic. SURMA: Let's go with black hole. It's like a new frontiers
kind of approach to things. So let's go with that. MARIKO: Yep. So let's creae a WebWorker-- worker new worker. And then I need
to pass the file. So I need to make new file. SURMA: Oh, new file. MARIKO: What's the
shift key for this? [SIGHS] [LAUGHTER] SURMA: Every key
is different here. MARIKO: Yeah. Worker JS. So now I can
reference this with-- SURMA: So that will
basically just download-- the browser will go
down at the file, create a new JavaScript thread,
load that file in the thread. And then you have control
of a separate thread just for itself. MARIKO: So as I mentioned,
worker takes a listen to on-- ah, let's say the
post message first. So I created the worker. I want to pass the
data to worker so that worker can deal with it. So worker dot post. Is message M capitalized? Again, API is so hard for me. SURMA: 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 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 just do a little
JSON style object. Be like, this is
what I want to do. This is my parameters,
which is probably what you want to do right now. MARIKO: Yeah. So I created the post
message, send 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 would you do this? Self dot message on message? What do you usually do? SURMA: 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. MARIKO: Do I need to
reference anything here? SURMA: No, you can just-- MARIKO: Oh, interesting. SURMA: Yeah, I know. Right? MARIKO: Because I
think, on the drawing, I still use the
self dot on message. I think I just use whatever
the Google Developer site explains to me. Or maybe HTML5 Rocks
explained it to me. SURMA: There's probably an
HTML5 Rocks out there for this. MARIKO: So message
event will be fired. And let's see-- so this,
let's call D, data, should be the data we passed. And I want to see what
this looks like, actually. So again, console log,
the greatest tool. SURMA: 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 to debugging. MARIKO: What is duo? Index 44-- something
is not working. Oh, oh, oh, oh, because we're
not using that image anymore. We're directly loading
that to the thing. SURMA: Correct. MARIKO: 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 went. And then inside of that, I
have data where data is exactly the representation of the
image data we dealt with. SURMA: Yeah. MARIKO: So inside
of the Worker, I get to access data
dot data dot data. SURMA: So this was a big
image, but transferring it was surprisingly fast. Why? MARIKO: Oh, well supposed to
be this shouldn't be fast. SURMA: True. Why was it fast? Either way, so the image data
contains an array buffer, a typed array buffer. And typed array buffers
are JavaScript versions of actual chunks of memory,
rather than abstract objects you can pass around. And post message 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 thread will lose access
to this typed array buffer, and the worker will get
access to it, right? MARIKO: Yep. So basically, let's say you and
I are a memory field, right? I have this image data here. And then I want to
pass it to Worker. Worker, if I don't,
on this line 44, if I don't have anything specified-- SURMA: We copy it. MARIKO: --then this is literally
copied into your field. SURMA: Yeah. MARIKO: However, if I specify
an argument, which we'll get to, then it basically just
moves the pointer. SURMA: It moves ownership. MARIKO: Yep. SURMA: Like you'll
lose ownership. I get ownership. And no copying needs to happen. MARIKO: Yep. SURMA: And that's good. MARIKO: And it's
the weird API where you have to pass an array. SURMA: It's a bit weird. MARIKO: And specify things. So in this case, image data
dot data is the typed array. SURMA: That's the actual array. MARIKO: Yep. Dot buffer. SURMA: 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 a series of floats or a
series of 8-bit integers. And we want to
transfer the buffer, not the interpretation
of the buffer, which is I guess the distinction. Which it's sort of a bit weird. But maybe that's a good
way to think about it. MARIKO: Yeah. This is a little
quirky bit that when you're dealing with 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 D 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-- SURMA: The face red operation. MARIKO: Well, warm filter,
not the face red filter. SURMA: I like face red
operation much better as a name. It seems like better
branding to me. MARIKO: So I have a whole
bunch of weird references that I need to-- so let's say,
width is inside of image data. So width W is image
data dot width. Height is-- SURMA: Oh, you're just
making it more readable. That's good. MARIKO: Yep. Dot and then data. The one that we are actually
dealing with is image data. So now I need to tweak
this a little bit. Oh, just-- ah, [INAUDIBLE]. SURMA: Backslash. MARIKO: Ah. W-- oops-- height, index. SURMA: Yes. MARIKO: This will
be W and data index. SURMA: All right. It's just data now. Yeah. MARIKO: Mm-hm. SURMA: All right. So we sent 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? MARIKO: Yep. SURMA: OK. MARIKO: So we need to send
it back on a post message. So wait. If you are in the
[INAUDIBLE] event listener, how do I send it
to post message? SURMA: Isn't that global? Just post-- I think in
Workers, it's just the global. MARIKO: Self to post message. SURMA: Yeah, just
go post message. MARIKO: OK. SURMA: It gets more
complicated if you talk about ServiceWorker. Because everybody can
talk to the ServiceWorker, but the ServiceWorker can
talk to all the open website. So you actually need to define
which window to talk to. And that's a whole
different story. In this case, we have
it nice and say, we just call post message. MARIKO: Yeah, it's weird for
me to not reference self. But I guess if Jake says
self is not necessary, then it's not necessary. OK, so supposedly,
we do all the things and then use the
post message to send the data that it was passed. Because we manipulated inside
of that data in this follow-up. SURMA: Wait. Is D the data? Or is D the event? Because you're not sending back
the event, and you want to-- MARIKO: Oh, that's true. So I have to do the
image data, yes. SURMA: And also you have to do
the transfer bit again, right? MARIKO: Yes. SURMA: Sorry. [LAUGHS] This is where you
can tell 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've got now. And this all works. So we'll make it work. MARIKO: Yep. So now, sent it, but then
we need to listen to it. So we can-- ah, this is
[INAUDIBLE] doing it. Would you do it outside
of this function? SURMA: Yeah, you've
done it so far. Why not? Yeah, just do the-- MARIKO: [INAUDIBLE] an
event listener message. And let's see. Inconsistency, let's make
it D. And if this pattern is repeating, then D dot
data should be image data. SURMA: Sounds about right. Ah, we're copying and
pasting lines now. This is typical reuse. MARIKO: And then put that
data into the canvas. SURMA: All right. I'm nervous. MARIKO: Let's hope this works. Yes! SURMA: 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. MARIKO: Record. Set it. Done. How's that? SURMA: OK, that
looks pretty short. And we can see the
dedicated Worker thread is what we are using. It has some work to do. MARIKO: So function
call to Worker JS, happen in dedicated
Worker thread. SURMA: OK. MARIKO: So previously, all of
this part was clogged inside. SURMA: You can mark regions
with shift, by the way-- shift and click. MARIKO: Shift and click? What? SURMA: Shift, click, and
hold, and it can mark regions. MARIKO: Ooh. SURMA: And it can measure
how wide they are. MARIKO: Ooh. TIL. SURMA: Performance pro tip. MARIKO: So previously,
this whole chunk of yellow was living in here,
which means it was blocking users' interactions. If they want to
click on something, or you want to do another
JavaScript operation, it was just blocking. SURMA: Yeah. MARIKO: And now you put
it into Worker thread. SURMA: I mean, the ultimate
test now is load the big image, right? MARIKO: Yep. SURMA: And see if we
have a six second frame, or if the frame
rate keeps going. MARIKO: Something better, right? Yeah. So let's do record-- SURMA: Recording. MARIKO: Big image. SURMA: Get that cat in there. That was also quicker. MARIKO: Yeah, visually quicker. SURMA: So here's an
interesting fun fact, something I recently learned--
if you look at the bar graph at the top, 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. That's good. And as you can see,
there is no red bars. Because we're never blocking the
main thread with this version. Because we're using
de-code image, get image bitmap, create
image bitmap, and the Worker. MARIKO: Yeah. SURMA: So good. MARIKO: Yeah. So That's pretty much it, right? SURMA: Nice. MARIKO: Do you want
to do anything? Do other things? SURMA: No. I mean, we're perfectly
on time, once again, as on Supercharged,
it is common. Thank you, so much, for
traveling all the way just for this. MARIKO: [LAUGHS] You're welcome. SURMA: As Mariko 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 to everybody for coming
and talking to us in the chat. It's been super active. I was really, really
happy to see that. As I already
announced on Twitter, this is the last Livestream
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 Mariko, not me. Or me, you can ask me too. MARIKO: Yeah, Twitter, or they
can ask ChromiumDev Twitter. SURMA: Also good, ChromiumDev. We are pretty responsive there. MARIKO: Yeah, which actually
we are the two active persons who's watching that. SURMA: You are mostly
going to get replies from either Mariko or me if
you tweet at ChromiumDev. If you want to stay up to date
with Supercharged live streams, microtips, maybe even totally
tuning tips, who knows, subscribe to this channel so
you get little notifications when we put up a new video
or we go live the next time. Thanks, for watching. And I will see you all in 2018. [THEME MUSIC]