 Hello. Welcome to WorkerEye's JavaScript Made Easy. So my name is Ben Morse. I'm a developer advocate at Google. My job there is to help the web be more beautiful and faster and easier for both developers and for users. Really easier for developers to make good experiences for users. I used to be a musician, which makes me especially sad that I can't be here in Austin today. I was looking forward very much to being in Austin, it's a great city. I used to go a lot for South by Southwest and has great music, barbecue and so on and so forth. Here I am instead in New Jersey. But hey, let's travel. My dog is over here. It's comfortable. So there's always that. Anyway, if you're here at this conference, you're probably a big fan of JavaScript. Why shouldn't you be? I mean, JavaScript is awesome. It does all kinds of incredible things. It's blossomed in the last years from this little thing to make small button changes and little things on web pages, to the full featured programming language ecosystem environment with lots of wonderful libraries and frameworks and features that are great. The thing is though, it's possible to have too much of a good thing. This actually is a screenshot from a Chrome Dev tools of a site owned by Google. If you have a lot of JavaScript, your wonderful site may load slowly for many people and also may execute slowly. So things on your page may not work sometimes because you've got lots of JavaScript running and things can happen in the browser. If you've got a nice device and you're on a nice connection, then it may not be quite as important. But for a lot of people in the world, this matters a lot. I mean, for me, for example, if I wanna train somewhere, trying to go somewhere, some sites that you try to load up don't work at all. Some sites do work, some sites don't. And people across the world may not have like a nice new iPhone, a nice new Galaxy phone or a Pixel or something. They could have a lower powered phone, which is quite likely. They may be also on worse connections. And in fact, last time I saw actually 40% of connections worldwide, mobile connections, were 2G connections. 2G is not how you can load a complicated JavaScript filled website. I mean, a lot of the problems are large images, other kinds of things can be problems, but we're gonna discuss JavaScript today. That's why certain people around the world are trying to look at your site and instead they're getting frustrated. So this is not good. Let's focus on the JavaScript side of things. What can we do as JavaScript developers to make these sites load faster and be functional more quickly? One thing, of course, is shiplash JavaScript. Okay, great, how do we do that? Well, you can minify and gzip our code, of course. You're probably already doing both these things, but people don't always minify, don't always gzip, send less code over the wire, at least it will load up more quickly. Also, of course, code that isn't being used shouldn't be on your page. It happens a lot because you have code for all of your site, which you put on all your pages on your site, but in fact, that makes things just slower for the user. You can also go through the code coverage tool of Chrome and realizing that I'm missing an S and unnecessary. Yeah, so that was necessary, but it's not there. Anyway, that S was necessary, it should have been included, but don't have to assure you, if you have extra code, don't include it on your pages. Also, if you're using frameworks or using various kinds of ways to move code and merge it together, reduce your bundle sizes, make those more efficient. If there are dependencies that shouldn't be there, get rid of those things, that all helps. It's also possible to load code when it's needed, so a bright before an interaction is going to occur, load the JavaScript then, like lazy load it, don't load it all at once, and block rendering until everything loads. Or of course, you can use AMP, which you know I talk about AMP quite a bit. AMP is a way to use less JavaScript and make pages load faster in general. So there's all those things. None of those really deal with the problem though of making things, making interactions happen more efficiently. Like JavaScript can be running and it can be blocking the browser from doing things. Long tasks can make things not able to happen. There's a way to get around this, which is web workers, because the web is single threaded, but web workers run in another thread. So you can offload code that is gonna take a while to run into a different thread via a web worker. Kinda neat, right? That way your code is running over here in a different thread, and your other code can keep on handling events, the browser can keep on doing things. But what is this about the thread thing? Why is the web single threaded? I mean, every modern OS is multi-threaded and multi-tasks. Why can't the web do this? Well, part of it is that it's just how browsers in JavaScript were created, how they've always been. Now, of course, modern browsers multi-task. You can run various tabs. They can be loading files while doing various other kinds of things and painting the screen, but the thing is that each browser tab has a single thread for the UI, which means only one process can make changes to the screen at a time. So JavaScript can block the browser from doing things and vice versa. Imagine it wasn't that way. Imagine if you just allow JavaScript tasks to run simultaneously. They can all modify the DOM at the same time, and while the browser's laying out and painting the screen, this task is modifying the DOM, this task is modifying the DOM, you'd have race conditions and general chaos. It would not work. It's confusing though, because as we know, JavaScript is asynchronous. JavaScript depends on events getting fired as async. So doesn't it, isn't it the kind of thing where as soon as an event fires, code executes immediately? Well, it's not actually how it really works. Remember that all the code on a single webpage runs in a single thread. There's a thing called the event loop. Let's look at this diagram here, rather not diagram animation. Anybody take Archibald, which I borrowed for this case over here. This is a simplified version of JavaScript's event loop. So the browser fires an event, right? If there's an event handler for that thing, that could run until it's done. As other events fire, they get added to a queue. So we're gonna see over here these tasks move into the loop there they are, it gets handled, another task is being queued up, and event loop handles that one next, all well and good. So really, if this works out nicely, the browser's able to get the tasks pretty quickly and there aren't delays. However, if a long task happens, it has to wait for that task to finish. Nothing else can happen until that task completes. So the next bit of code will be delayed. This also means the browser may be blocked from doing things in the UI. You may be blocking the browser from entering things into a form, you may be blocking scrolling from happening, animations might get janky, and of course if the person taps on something else, while your code is still running, that event can't get handled until your code finishes running because it's all one event loop, it's all one thread. So that can be a problem, you can get this case where there's traffic holding up the entire thing happening in the DOM. We wanna avoid this happening. Not only do you have JavaScript causing pages to load slowly sometimes, but it makes this unresponsive screen where you can't swipe, you can't do things, users don't like that sort of thing. So one solution for this is to use web workers. Web workers are special because JavaScript in a web worker runs in its own thread, which is nice. Web workers have been around for quite a long time, actually about 10 years. So why don't they use more? I think because their limits make them harder to use. The thing is, workers can't cause those race conditions in the DOM and can't get in the way of other kinds of things because they lack access to the DOM, they also lack access to the global scope. They can't modify variables that are in the global scope. So they're limited. You can kind of pass them things and they can then send messages back. That's how they work. They work by passing messages back and forth. So web workers can pass messages to the main thread, which can pass messages back to the web workers. That's about it. Now that's kind of complicated. There are libraries that make this easier like a com link by Surma and workerized by Jason Miller, but even with those libraries, workers can't access the DOM. They're stuck in this little DOM area over here where they can't get near the DOM. That's a big obstacle. Fortunately, there's a new library called Worker DOM. This was released by the AMP project a couple of years ago. Worker DOM works in the following way. It makes a copy of the DOM the worker can use. And Worker DOM also recreates in its own JavaScript a subset of the standard DOM API so the worker can manipulate the DOM and make changes on the page using standard DOM methods and properties. It looks sort of like this. There is a copy of the DOM, if you will, a virtual DOM which Worker DOM creates and there's a real DOM. And the Worker DOM creates the two DOMs, a lot of DOMs here, sorry. Worker DOM keeps the real DOM and the virtual DOM in sync. So when a change is made in the real DOM, Worker DOM detects that. It diffs it and detects it and sends a message over to the worker telling it to go ahead and make the same change in the copy. If your worker's code changes its copy, Worker DOM recognizes that mutation and sends a message over to the real DOM making the same change over there. It's a little bit of overhead, but it's actually pretty fast. Here's how it kind of looks. Worker DOM handles mutations in this way. It does a diffing of the virtual DOM and the actual DOM which sounds kind of like other frameworks we've used before. An efficient diffing mechanism figures out what changes and then it encodes those changes into an array buffer, a very compact way of sending a message over to the other thread that has to make the change and then passes it over. Here's an example of that. So for example, this kind of standard looking thing here, document create element div gets represented in the following way as this very compact looking series of numbers. The first number there represents the reference to the node which this div here will be always index number three. The second number tells the main thread what kind of DOM mode is being created. Element mode happens to be number one. Then the node name of div corresponds to six and so on and so forth. So any kind of mutation gets encoded into a small bit of numbers. That's why this message passing actually isn't that slow. I think SIRMA actually has a whole blog post about this where he discusses how it can be pretty fast. He does some measurements about this. So worker DOM does this for you but it's still a little complicated. You might be telling yourself, okay, so I can try this thing out, this worker thing, but how do I use it? Do I have to build this myself? How do I use this whole worker DOM thing? Well, the good thing is there's an easy way from the framework that wants to make things easy for developers and advanced web features accessible to all, which of course is our friend AMP. As you probably already know, was created by Google as an open source project. The goal being to make the web faster and easier to use and just better in general. AMP is now part of the OpenJS family. It's why I'm here today. AMP is now an OpenJS growth project. To you, AMP may just be a way to get into Google's top stories carousel, which has a special place in. If you do that, you may also know that Google has just announced recently that in the near future, any page that meets new standards for speed and for a stable layout, which are called web vitals, any page that meets these standards will now be eligible to be in the top stories carousel, not just AMP pages. In fact, AMP pages that are slow or unstable won't get in there anymore. This is not true now, but this will be happening in the very near future. So you may have thought of AMP in various kinds of ways, but probably not as a way to make developers' lives easier. That, in fact, is why I'm interested in AMP because it makes things easier for developers for common and basic tasks. What is AMP? It's basically a web components library. So HTML was created about 30 years ago and it was a document description language. So there's things like, hey, this is boldface. Hey, this is a paragraph. There weren't things like, hey, this is an interactive menu. Hey, this is an image carousel because those things didn't exist yet. As those things became part of the web, JavaScript grew to the task to make these things happen, to make interactions happen. HTML couldn't do those things, which means that people ended up adding a lot of code to their site, which isn't always necessary. So AMP aims to make this better by using web components to add new tags to HTML that do those kinds of things that HTML didn't do before. You see some examples over here in this large list of colorful looking names, things like a flying carpet effect, a Facebook comments component, the AMP carousel component, all kinds of things. I think I see a Hulu player over there. All of these tags here work because they're web components that are run by small bits of JavaScript that AMP uses. I'm in contrast, AMP discourages you from writing your own JavaScript because that can make things slow. That was the idea of AMP. It's now allowing more JavaScript to be written as we'll soon see. Before we see that though, here's how AMP looks in practice. This is simply how you do YouTube embed in AMP instead of embedding YouTube's own JavaScript, use a component called AMP YouTube, specify a layout type. AMP has various layouts, including responsive, which is its way of automatically making the YouTube video or any component shrink if it's container shrinks or expand if the container expands. And the width and height are specified in advance. That's because AMP wants to prevent things from shifting around on the screen and wants to prevent content layout shift. So it creates a space for everything in advance. And then as things load up, they pop into their space, things that move around, the browser isn't repainting the screen, recalculating the layout, things are just faster and more stable. And finally here, we have data video ID, simply the ID of the video, the YouTube video. And then you just do this and there's your YouTube video all done. So I was saying before, worker DOM, amp makes this possible to use through a component called AMP Script. AMP Script is kind of a wrapper around worker DOM which brings it into AMP, makes it pretty easy to use. How does this look? Let's try a simple hello world example over here. So hello world, let's see. In the body, we're gonna insert this AMP Script component over here. This is just another component in AMP. It's got layout type equals fixed because we'll see why later. We give it the name of a script, we give it the size of the components because as we know in AMP, all things have their size declared in advance and it consists of the word hello instead of h1 tag. Now what AMP Scripts will do is pass the stuff inside the AMP Script component, the children to the worker as the entire DOM. So the whole DOM the worker sees is just the h1 tag. Then we have the script over here which simply grabs h1 tag and it pens a comma a space in the word world and there you are. Notice that we have type equals text plain instead of text JavaScript. This is so the browser doesn't see this as a script and execute it. Instead it's just plain text, AMP Script can grab it and give it to worker DOM to use. There's that. And let's see if we can get this thing to actually work. I think that's the next thing over here. All right, I'm gonna make a new tab over here and I'm going to enter over here the URL of my little demo. That's actually not what it is. It's actually supposed to be this AMP Scripts. Getting closer now. Thank you auto completion for almost being there. This is it. Hello world, okay. Hey, I'm clapping for myself because no one else is here but me and my dog. Hello world. So what did that actually do? Can you see that actually worked? You can't tell what it actually did. Let's look over here at the console either at the sources. We can see here at the bottom of the sources and DevTools, this little extra thing, this thing over here. And there is this little bit of JavaScript. And the top over here, let's make this a little bigger. I said get a little bigger. Thank you very much. The top over here is worker DOM stuff and the bottom is our JavaScript. So there it is. We actually managed to inside a worker add this little world thing over here. There you go. That worked. It wasn't gonna be that exciting. So by the way, this is a little more of the page it can go in. So this is more of the AMP page this would be part of. Notice that the first thing we do over here is we load up AMP so in runtime, which makes AMP possible. I also load up the bit of JavaScript that encapsulates worker DOM that makes AMP script work. So you can also put this JavaScript into a different file instead of putting it in line. In this case, we've just stuck the JavaScript into a different file called helloworld.js and pointed the source attribute of AMP script to that file. There we are. A more glamorous example here is an event handler. So we've added a button to our HTML over here, this button that says hello who and added some more JavaScript that adds an event listener to the button where if it's clicked, it adds the famous comma in world. Let's try this out over here. I think this is called hello button which I named very, very cleverly and let's make this a little, whoops, that's not what I wanted to do. There we go, okay, make that a little smaller and hello who, look at this, hello world and more worlds and more worlds. Now the document we use over there, a document object is not the same as the one you usually see. Let's add a break point over here and run this thing again. Run it again, okay, let's go to the button. Notice a document over here is not the usual document. It contains the things that you wouldn't usually see. Look at this, a seven, an eight, a nine, some arrays, a T, some more things over here. This is because this document object is not the one the DOM provides, the browser provides, it's created by worker DOM and worker DOM gives you all these things to simulate a DOM. Kind of interesting, kind of neat, that's how it works. So there's that, there is that JavaScript over there. Okay, and you can do more in a worker. Workers actually natively support fetch, XMLHTTP requests, web sockets, canvas, all kinds of features like that. Here's a fetch version, let's try that one. So again, we just have a fetch instead of having the thing just stuck in there. You click on the button and then you fetch it. Let's go over here and see how that works. So here's hello fetch. Actually let's go over here to the network tab and see if we can watch this being added. So there's what's added over there. We're gonna click hello who and notice hello text was grabbed over there and it contains the incredible payload of comma world. There it is. All these things are not so complicated and a way to get JavaScript into a worker, which is kind of neat. Remember though, this is actually not again the real document API. Remember that worker DOM has gone and recreated these things with its own JavaScript. Here's an example over here. I've got elements by name. This is the code that worker DOM itself uses to get elements by name. So all that is true. The thing is that you can't really have worker DOM reproduce the entire DOM API because it is absolutely enormous. Sorry about this cut here in the video. My dog got bored and went downstairs and was stuck inside the downstairs area. I couldn't get out and there was some general chaos for a little while, but now we're back. So I think I was talking about where we were over here. I think we're somewhere over here in the previous slide. There we are that worker DOM recreates these APIs with its own JavaScript. It doesn't recreate the whole DOM API because it just couldn't do that. So there is this handy web compatibility table over here, which you can find at go.amp.dev slash amp script APIs. This provides a list of APIs that are and are not supported. So you can go through your JavaScript and if things aren't supported, replace them with equivalent APIs that are supported. There are also a couple of limits that amp script places in there so you don't violate web vitals principles, don't have things loading slowly, and then have layout shifting around on the screen. One of those things is amp script doesn't allow more than 150K total JavaScript per page. If there were use cases that required more than that, the team would consider raising the limit, but so far no one's really complained about it because it's usually used for the tasks amp doesn't really do out of the box. You just want to change something here and there to add some kind of functionality. The other thing is that it wants to restrict intrusive mutations. So if your amp script tries to make changes before user action that will make the screen move around too much, it will try to block you from doing those things. So you can get around or rather you can make your amp script more capable by taking some simple precautions. Amp script knows that if your layout is a fixed type, then that can't move around too much. Like if the children of your amp script area change size, the whole container won't change size. If the height and width are fixed in HTML, it knows the whole amp script area can't change size. So if those things are true, if the amp script area really is fixed to a certain part of the screen, it says go ahead, make changes over here. If it isn't fixed to a certain part of the screen, it says, you know what, you can't change things all over the place until users take an action to request a change because it would involve a lot of things that would surprise the user in terms of layout shift. It's kind of a more elaborate topic. So to hear more about it, go to amp.dev and read about the actual ways that keeps this safe for you. So again, I was saying before that WorkerDOM has certain APIs. If you wanna not worry about this too much and just go ahead and write your code, have it work out of the box, you might wanna try one of your favorite frameworks. The team that works on WorkerDOM also works on various frameworks and uses them frequently. And they have tried using amp script with things like Vue, React, Angular, Lit HTML, Aurelia. The thing is that these frameworks use a certain specific subset of the DOM API to do their own changes. They do a diff between the virtual DOM and the actual DOM, and then they use certain APIs consistently to make changes. So WorkerDOM supports all of those things well. However, you may find yourself with larger bundle sizes with certain frameworks. So to make your bundle sizes small and to really follow the principles of amp that you should have less JavaScript, no more than you need, and keep things fast for the user, recommend that you use Preact. And Preact, actually one of the people that works on the WorkerDOM team as part of the Preact Core team, he was very careful to make sure that the APIs that Preact uses are well supported within WorkerDOM. So Preact actually is like React, very similar. It's compatible in most ways. You can always transform React into Preact, but it's only 3K minified in GZipped. So out of the box, not much extra JavaScript being added to your project. And actually amp itself is being rewritten with Preact. Amp is being recreated so that all the components will work reliably by themselves, not using the up-run time at all. This is possible usually now, but not guaranteed, but to make it more part of the web, this effort's being undertaken. And it's being undertaken using Preact. So the app team's very invested in Preact. So in the spirit of that, I took my Hello World example and we did it with Preact. It's not that much more complicated. It's just a component and the usual kind of JSX things. Let's now drag this terminal here into our visible window. There it is. Let's build this suspense, suspense, suspense. Suspense, suspense. Let's serve this. Now let's drag this out of the visible area and let's try this over here. It's an embarrassing moment. I can't type anymore. And that's a bit of a problem. Actually, I think it's, I wonder why it's there. Interesting. There we go. And Hello Who. Hello World. There it is. Magical. So Preact works. So that's my discussion here about workerized JavaScript made easier by AMP. If you wanna learn more and try this yourself, we just updated this tutorial here. It's quite nice now. Go to go.amp.dev slash learn script and you can make your own custom UI widget that does some form validation. It guides you along and teaches you about the various things that AMP Script and WorkerDOM do on the way. So look at WorkerDOM's code to get involved in the project. Just go to github.com slash amp project slash workerDOM. And yeah, try it out. We think that workers are a way to make JavaScript more friendly for the user and getting the users way less often. There's various ways to use workers and the way that AMP provides makes it simple to get started. Try it out. If you like it then go from there. Thanks a lot and have a great day.