Patrick Hamann | WebAssembly – To the browser and beyond! | performance.now() 2019


– Thank you, Tim. Hello, welcome. Hello, Amsterdam. Firstly, thank you for
that introduction, Tim. And thank you to the organizers for inviting me to be here
in this wonderful city and share this stage with so
many other wonderful humans. I’m honored and privileged to be here. My name’s Patrick Hamann. As Tim said, I’m a principal
engineer at Fastly. And you can catch me on the
Twitters there, @patrickhamann. Although, I might stress I’ve
actually taken a sabbatical off Twitter for the last year. I encourage you all to do it. It’s amazing. It’s very healthy. But I’m back, and I’m
gonna start jumping back in on the conversation there. But please come and
talk to me in the break or at the party later, about anything I talk about today, or just tell me what you’re up to. I really love to hear what
people are doing in this space. I work at Fastly. We’re an edge cloud platform that the world’s largest brands use to deliver their content
as fast as possible. And at Fastly I work in a team
called the office of the CTO. It’s an emerging technologies group. We’re inside the engineering organization. And I want to talk to you about one of my newly found
passions as part of this team that we’ve been looking at
for the last two years now. And that’s WebAssembly. I’m gonna discuss why we
even need WebAssembly, what is it, how you can use it today. We’ll look at some practical use cases that people are already doing and the benefits, the speed, and the performance benefits
you’ll get from this. And finally we’ll look at
how WebAssembly can be used actually outside of the browser,
which is an amazing thing, and what the future holds for it, especially with the new standards and specifications that are coming. Before we discuss what WebAssembly is we need to take a step back
and look at the history, and look why does it exist. And so, let’s talk about the Web platform that you all know and love. For the last 20 years, the Web platform has largely consisted of these three technologies. HTML, CSS, and JavaScript. Initially we had HTML that was created by researchers at CERN as a way to share
information and documents by way of hyperlink. Then we realized that we
need to separate that style from the documents
themselves, and we had CSS. And then finally, as
web adoption increased, and interactivity and the
dynamic nature of the Web became more demanding,
we introduced JavaScript. We realized that we needed
a glue language, as such, that was easy to use by programmers, could be embedded
withinside a web browser, the runtime could be embedded, and even the scripts themselves could actually be embedded
within markup, withinside HTML. And I think it’s a true testament to the design of these languages that they have lasted so long and held up against the test of time. Occasionally we’ve had romantic flings to Adobe Flash and Java applets that have tried to change
how we program on the Web, but they didn’t last, and there are reasons why that happened. But these three technologies
have remained the same. It’s truly amazing. Later, with the birth of Ajax we could request fragments
of the documents, even just data payloads, JSON payloads. And our servers could stitch… Sorry, our clients could
stitch these together into the DOM, dynamically, and interactivity just
dramatically increased. And so, with the likes of React and JavaScript frameworks and
single-page web applications, most of the heavy lifting is
now happening on the client. We’ve moved from that model
of thick server, thin client, to thick client, thin server. We’re doing more and more
compute now on the client. Some of you may think that’s a good thing. Some of you may think that’s a bad thing. But we’re definitely seeing
this paradigm change, this shift in paradigm. But is that really the best model at all? Or rather, is sending megabytes
of JavaScript to the client really the most efficient
use of those resources? Especially when mobile devices vary dramatically in
their compute performance. Or is the client the best
place to run that logic? Or there are some things that
we do on the server today that actually should be run on
the client to reduce latency, if the client has that compute power. JavaScript was designed
to be easy to use, safe, high-level programming language. What I mean by a high-level
programming language is it’s a language that can’t
directly access memory, whereas a low-level language is a type that can actually have impact
on the underlying hardware and the physical memory that we write to. But it also means that, because
it’s a low-level language, we can’t optimize that language to be efficient on the hardware
that we’re running it on. And again, this is really important when we have low-end devices that the next billion
are coming online to use. And it’s written and
distributed in plain text. That means it’s
interpreted in the browser. It’s an interpreted language that uses just-in-time compilation, so every time we load
a new JavaScript file we have to compile it on
the fly in the browser. And it’s only a single ecosystem. Now, don’t get me wrong. It’s an extremely large ecosystem. In fact, it’s the largest programming language
ecosystem in the world. But we can’t benefit from tools that have been written to solve
problems in other languages that are well hardened
and have been around for many, many years. And so, that slide seemed like
I was hating on JavaScript a bit too much, which I’m not. I traditionally am a JavaScript developer. It is the most ubiquitous
programming language in the world. And the Web has succeeded
because of JavaScript, and JavaScript has succeeded
because of the Web. But the problem is that, on
the Web, on the Web platform, all we have is JavaScript. You don’t have a choice to drop down to a lower level language if you want to. So if I’m programming on the server I could just, say, use
a program like Ruby. It’s a high-level language,
but it’s productive. It allows me and my developers to get things done quickly. But when we need to drop down
to a lower level language like C or C++, when the
problem needs to be critical and run as fast as possible, we can. We have that freedom on the server. But on the Web platform,
we don’t have that freedom to drop down to a lower level language, if and when we need to, for certain
performance-critical operations. So what can we do about this? We could implement the C++ runtime or the Go runtime in web browsers. But this would be, one,
a security nightmare. Those languages have access to memory. I don’t want to allow any third party that I download inside my
browser, or my customers download, to access my memory directly. That would be a security nightmare. It’d be a maintenance nightmare. I’d have to remember that, oh, Chrome 74 ships
with the Go 1.4 runtime. Again, that matrix of possibilities
would just be too much. It just doesn’t scale. And so, this is where a team at Mozilla started to think about how
we can solve this problem. And they created a tool called Emscripten. Many of you might have heard of it. It’s a C to C++ JavaScript compiler. Or initially it was a JavaScript compiler. And this allows anyone to compile
a C program to JavaScript, to just raw JavaScript. The problem with this is that it shipped with a really bloated runtime because they had to recreate
all these system calls like the file system, or
making network requests, as a JavaScript wrapper around this. The bundles that this produced
were in 10s of megabytes, especially if you were
compiling a large C program. But they started to notice patterns in the compiled output of that JavaScript, especially when it came to
managing numbers, and arrays, and memory, and bytes in memory. And they created a subset
of JavaScript called asm.js, which you might have heard of. And what this allowed
to do is that they could optimize their JavaScript engine to run that code extremely efficiently if it was only just managing number types and bytes in memory. And the really interesting
thing here is that when they were compiling the C program the memory space that it used, they said, okay, we’re gonna allocate memory as a JavaScript array
buffer, and that’s it. It’s gonna be a fixed size. And that meant that the C program couldn’t then access
memory outside of that. It literally was just a typed
array buffer in JavaScript. And so other browser vendors
started noticing asm.js, and they started to optimize
their own JavaScript compilers to be able to run this code extremely, extremely efficiently. And this is where WebAssembly comes in. All we had was JavaScript. And asm.js, all we could do is, even though it was a subset of JavaScript, we could only optimize it so much. It still had to be delivered
via plain text in the browser and interpreted and parsed, and that compute still
takes a lot of time. So on 2015, the WebAssembly
Working Group was formed and the whitepaper was released. And it came out of this
work that Mozilla did, and asm.js did, and Google did, on a program called NaCl,
which is Native Client. And it has all the
things that you’d expect from a standard on the Web platform now. It has a working group, it has standards. You can go and look at
them on W3C, et cetera. Hopefully now we’ve got an understanding of how WebAssembly came to exist. Let’s look at what it actually is. And many people just think
it’s C++ for the browser, and it definitely isn’t
that, and it’s so much more. Let’s talk about what it isn’t first. It’s not a programming language. You don’t actually write it by hand. It’s a compilation target. So you write other host
languages that compile to that. But I like to think of
it as just another tool in our toolbox that we can use to solve certain problems
on the Web platform and extend the Web platform beyond the capabilities
that it had before. So it’s a compilation target. It’s for other languages to compile to. You don’t write it yourself. You write a host language,
say Rust, or Go, or C++, and then you compile that language to it. If we were to look at
the WebAssembly website this is literally what it says. It says, “WebAssembly, abbreviated Wasm,” which you might hear me say throughout the rest of this talk, “is a binary instruction format “for a stack-based virtual machine.” Right now you’re probably thinking, or you might be thinking,
“W-T-F, Patrick, what?” And I definitely did the first time I started learning about it. Let’s pick that apart. A binary instruction format. This means it is a set of instructions for a machine to process that has been encoded in a binary format. Unlike JavaScript, it’s not plain text. It’s encoded in binary. And because of this binary format it means that we can natively decode, in the runtime in the browser, much faster than we can decode JavaScript. The initial experiments that Mozilla did for the WebAssembly whitepaper prove that WebAssembly can be
decoded up to 20 times faster than JavaScript can, in
a browser environment. And especially when we’re shipping large amounts of megabytes
down to a mobile client, where sometimes we’re seeing JavaScript that’s taking up to 20 seconds
on a low-end Android device to parse and execute, by being able to speed up
some of that to 20 times, you can see the performance benefits that we’re gonna get from this. Especially when combined with techniques like streaming compilation, so we can compile it as the
bytes come in down the wire, and better than gzip compression, you’ve now got a format, a
binary instruction format that is designed to be ran extremely fast within web browsers. It’s a stack-based virtual machine. There’s very different… There’s a couple of different ways that you can represent
a machine like a CPU. One of those is stack-based, and the other is register-based. The CPU in your device
right now is register-based. But you don’t really
have to worry about this. What’s more important is
that it’s a virtual machine. It’s a processor that
doesn’t actually exist. We’re not writing the WebAssembly to run on a specific processor, an x86 or ARM, some specific hardware. We just need to compile it
for this virtual machine, much like the JVM, the
Java Virtual Machine, if you know about that. And the cool thing about this is that the compilers, the languages, Rust or C++, don’t have to know about
how the hardware works. They all can target this
one virtual machine. And that makes it really portable, which is one of its greatest benefits. WebAssembly’s spec is pretty simple. It’s like this. This is on the W3C website. It only knows about numbers, and bytes, and integers, floats, names in memory. That is the type system. It is that small. And it also has operations
and instructions that you can operate on those types, so like add, subtract, multiply. But the really interesting thing is that actually a lot of very complex programs written in these low-level languages can be reduced down to just
this set of numbers in memory, and then moving those
numbers around in memory. Most software that we write
actually boils down to that. So when you write some code
in a low-level language, normally the compiler will compile it to something that’s known as an IR, an intermediate representation. And then that’s the same regardless of the system architecture
that you’re compiling to. But then all these compilers
then have to have backends for each target that you’re targeting. So ARM for mobile devices, x86, which is Intel’s assembly instructions that maybe many of your laptops that you’ve got here in the
audience are gonna be using. And so, when you do that, as a developer in one of those languages you’ve gotta compile all your source code to six all different instructions. When you go and download
a binary, you have to go, “Ah, I need to find the Darwin x86 one “for my MacBook Pro
that I’m running here.” But with WebAssembly you don’t
need to worry about that. The code just gets compiled to the WebAssembly’s virtual
machine instructions, which is normally shipped
around in a .wasm binary file. And so the runtime then takes care of how that is converted to assembly on the machines that you’re running. And because the
WebAssembly instruction set has got that really small
API that we just saw, it’s really easy for host
languages to target WebAssembly. So some of the compilers, it only took them months
to integrate WebAssembly. And we’re gonna see that
adoption increase dramatically over the next five years. For it to succeed, WebAssembly
had a few guiding principles to ensure that we solved the problems that it was set out to do that I outlined in that first section. Firstly, it’s gotta be
a compilation target, we’ve just discussed what that means, so other language’s
toolchains can target it. It has to be fast to execute, and compact. And this is really, really important when we’re talking about the Web platform. When we’re shipping native code they’re normally quite large files. In fact, a lot of programs are already preinstalled
on your computers. But on the Web we don’t have that benefit. We can’t benefit from
any precompiled programs, and so we’ve gotta recompile
them every time in the browser. So it has to be as compact and as fast to execute as possible if we’re gonna be able to
ship native applications to the browser. And it’s got a linear memory model. And this is what I’ve discussed
about how Emscripten works, about only you’re supplying the program with a specific slice of memory and that’s the only thing
it’s allowed to operate in. And this is one of the most fundamental points about WebAssembly, is that it has a memory sandbox and so you, when you
instantiate this program, are only allowed to use
this array of memory, and it starts here, and it ends here. And so the program, it’s
physically impossible for it to go outside of that. And this makes it really, really powerful and also makes it really easy now for programs to be compiled to run safely. That’s the most important thing of untrusted native code in your browsers. To understand what’s happening here I think it’s actually
better to just visualize it, the relationship between
the source language, WebAssembly, and then the instructions that they then actually get converted to by the browser’s runtime. Here we’ve got a simple… This is a tool called WasmExplorer made by Michael Bebenita. He’s on the WebAssembly team at Mozilla. You can check it out there. This is a really simple C program. It adds A to B. A and B are integers. You can see here, this
is the stack machine that WebAssembly has created for it. We’ve got an int, i32, and we’re calling the
add instruction on it. And then you can see directly how this relates to x86
assembly in the browser. You can see that add operation. I’ve also lied to you. I said that WebAssembly
is a binary format, and this is text. How is that even possible? This is called WAT, which is
the WebAssembly Text format. And then assembly is
the text representation of the binary machine code. And so you can see, for
the first time ever, we now, if we want to, can have direct control on the operations that a program in our browser
is running on the hardware. Which, for me, is amazing. You might be asking what the support is like for one of these. The most exciting thing
about WebAssembly now is that it’s supported in all
major browsers, it’s shipped. This is the first language, since JavaScript shipped 20 years ago now, for the Web platform. For me, that is amazing. It’s across the entire Web
platform now, so you can use it. It’s over 88%, we can see over there. 88.39. To summarize, WebAssembly is
a new language for the Web. It’s compiled from other languages that gives us native speed, consistency, and reliability in the browser. And I’m gonna talk about
that reliability a bit later. And it’s the first time ever that we have a portable
representation of native programs that we can ship anywhere and
run safely in the browser. And for me, this is amazing. We now have a better understanding of why WebAssembly came to exist, and maybe an understanding
of what it actually is. Let’s look at how we can use it. We’ve got a new collection of JavaScript APIs that hang off the DOM that all are under the
namespace WebAssembly. You can invoke the exported functions that your WebAssembly module exports. Here this is exporting a
function called fibonacci, and I’m passing 42 into it. This is the preferred way of doing it now. Before, you had to synchronously load it, but here we can do the
instantiateStreaming. It uses the fetch API,
which returns a promise. And the cool thing about this,
with instantiateStreaming it means that as the bytes
are coming off the wire we can start to compile that program. Which means by the time the
full Wasm file is loaded we’ve actually already compiled it and we can then load it instantly. And we don’t get this
benefit from JavaScript. In fact, Firefox can now compile
your WebAssembly binaries faster than the bytes
come off down the wire, which is incredible. And if we combine that with things like implicit HTTP caching… Because the difference
between a JavaScript file and a WebAssembly file is that the WebAssembly will always
compile to the same machine code regardless of the input data. Whereas JavaScript, you
can do that, it’s tricky. JavaScript compilers are
extremely intelligent things. But they have to optimize that, and they can’t then cache the compilation. But with WebAssembly, the first
time that I’ve compiled it the browser can then store that compiled asset in the HTTP cache so the next time that file is
requested, it runs instantly. No downloading, no compilation. Instant, very fast, reliable performance. Let’s actually look at a genuine use case. Let’s imagine that I am
GitHub, or a news organization, and I want to accept comments in the form of Markdown on my website. I’ve loaded a Markdown parser
from npm, I npm installed it, and it’s doing the job for me well. But I profiled my application, and I saw that the hot
path of my application was when this JavaScript was compiling the Markdown into HTML. Because JavaScript wasn’t really designed to be a tokenizer and a compiler, and we’re having to write
a lot of code to do that. But I know that I have a Rust library that is very efficient
and solves this problem, and in a type-safe way, and I
wanna take advantage of that. To do this, we’ve made a little demo called markdown.fastlylabs.com. Let’s have a look at the code. I’ve chosen this example because it shows that you don’t even need
to know Rust that much to take advantage of preexisting solutions to problems that you may have. Firstly, I’m importing a
library called pulldown-cmark, which is our Markdown parser, and the HTML and parser
functions from that. I’m exporting a public
function called render that accepts a string
and returns a string. It accepts our input string,
which is the Markdown, and it’s gonna return the HTML. I then invoke the parser. I create a new HTML output string, and I write the HTML output to that string and then I return it. It’s eight lines of Rust. But… Oh, sorry. What you might have noticed here, I’ve also imported something
else called wasm-bindgen, and I’ve used a Rust macro
to decorate my function here. Why am I doing this? This tells the compiler that it needs to also generate
the JavaScript bindings to be able to invoke
this WebAssembly module. Why do we even need to do that? If we remember from the previous section, WebAssembly only supports
numbers and bytes, arrays, types. It doesn’t actually have a string type. You can’t just pass it
the Markdown string. And so this is where we need
to create some JS glue code that when you give it a string it converts that string into a byte array and then passes that byte
array, or the pointer in memory, to the WebAssembly module. But that’s a really annoying
developer experience for me. I have to remember how to
convert a JavaScript string every time I need to use it. And this is where wasm-bindgen comes in. Just by doing this it’s gonna automate writing
that JS glue code for me and just expose my Wasm module and the loading in the browser just as a normal JavaScript function that I can just import. And so I can continue to
program at this higher level, and just pass strings and accept strings and not have to worry about how that data is getting converted to numbers
and memory under the hood. This is actually gonna be replaced by a proposal called interface types, which I’m gonna discuss later. The next tool we’re gonna use
is something called wasm-pack. This is much like webpack but for Wasm. It’s made by Ashley Williams and the Rust WebAssembly working group. They’re doing some
amazing work in this space to try and make Rust and
WebAssembly more accessible to all of us as developers. And so, when I run this wasm-pack build on that Rust source code that we just saw it will spit out a Wasm file. So it’s compiled it for me. I don’t even need to know
how to compile Rust to Wasm. And a JavaScript file, which is that glue code that we mentioned. It’s even nice enough to
export some TypeScript type definition files for us as well. Back in our JavaScript application all we need to do now is import that file that wasm-pack has exposed and get our input element,
which is called markdown, and our output element, bind an event listener to the input. Every time sometime types, we pass that value to our render function which is exposed by the JS glue code, and that’s gonna call the Wasm parser. Then we write it to our output element. Don’t worry too much about this code. It’s in my slides, you can link to it. But I think it’s easier if we look at the
relationship side by side here that I’m exporting a
public function in Rust and then I can just call render
here and pass the string. This is how that JavaScript is calling into Rust via WebAssembly, but that’s gonna be compiled down to binary code and shipped, and run efficiently in the browser. With eight lines of Rust and
eight lines of JavaScript we’ve been able to replace
this really hot path in my JavaScript application. Let’s have a look at what that looks like. The interesting thing here is that I haven’t done any video trickery. I haven’t sped up the frames in this to make it look like
it’s as fast as it is. This is literally how fast it is. And I didn’t need to use a
debounce or throttle function. I probably should have
anyway, but I didn’t need to because it can accept the input that fast and return it to HTML that fast. For me, this is mind blowing. I think it’s pretty cool. We know what WebAssembly is. We look at one example of how
we can use it in the browser. Let’s have a look at a
couple of practical examples that people are using it
for in the wild today, and some of the research
that’s been coming out around this in the last year or two. PSPDFKit is one of the most prolific PDF renderers on the Web. Whenever you load a PDF
inside your Dropbox account, or you sign a PDF on DocuSign, or you read a PDF that’s embedded within a news article in The Guardian, they’re all using this library
called PSPDFKit to do that. Previously, prior to 2016, they only offered a native version that you could embed in your
native applications to do this. But then they realized
they needed a web UI. But when they first shipped
it, what they did is that when you loaded up that embedded
component on the web page it had to make a call back to the server. The server had to render
the PDF as an image, send that image back. And so for a large PDF file with 20 files, that’s extremely inefficient and causing a lot of
latency for the experience. But their core PDF renderer
is actually written in C++. So what they could do is that they can compile
their core renderer and ship that as
WebAssembly to the browser and now have the PDF rendered
directly in the browser, and you completely eliminate
all of those requests and that latency to do that. So I think it’s really cool. Squoosh.app some of you may have seen. It was released by the Chrome
Developer Relations team this year at Google I/O. It was an image compression tool especially for the performance
of us in this audience. It’s actually a really cool online tool. Think of it like Adobe
Photoshop but in the browser, and you can tweak settings of an image to see how well it compresses
before exporting it again. To do this, they compiled
various native libraries such as mozjpeg or
Google’s libwebp, from C++. So tools that weren’t even
written to run in the browser now can run in the browser via Emscripten. Then they just allow you
to change the settings. And all of this is happening in realtime, which I think is amazing. But the point here is that WebAssembly allowed them to
polyfill the Web platform for features that don’t exist. Yes, some browsers have
support for WebP, for mozjpeg, but some of them don’t. And so I can polyfill over things that don’t exist in the Web
platform using WebAssembly, using native libraries that
already exist out there. This is one of the key points that I want you to take
away from this talk, is WebAssembly’s not here to
kill JavaScript anytime soon. It’s here to augment the
holes and the weaknesses that JavaScript wasn’t
ever designed to do, or things that in the Web platform we’d not get round to standardizing. We can use WebAssembly to polyfill the Web but do that secure and fast. Part of that project,
they did some research. This is for one of the functions, which was the image rotate function that you just saw in that previous video. This is actually quite
easy to do in JavaScript because with the Canvas API all you’re doing is flipping
pixels in that array. They wrote that in JavaScript. But then they wrote
that same implementation in three other languages,
C, AssemblyScript, and Rust. And they compiled those last
three ones to WebAssembly. And then they benchmarked
these across four browsers. And the results are
really, really interesting. Point number one is that
some JavaScript engines, I’ll let the user determine what you think those browsers might be, are very, very good. Modern JavaScript engines
are amazing, and they can, if you’re only working
on memories and numbers, can optimize that code very, very well. But some engines are much slower. But then the really interesting thing is, regardless of the browser, the WebAssembly ones are
consistently fast across the board. What this shows is that
WebAssembly can be extremely useful when you need consistent
performance across the board. Think about those hot critical
points in your applications. I’m not telling you to use
JavaScript, not at all. I’m saying think about the
parts of your application that can be solved in another language and do that much faster, and you’ll get consistent
performance across the board regardless of the browser. eBay. In the eBay mobile app, when you are a seller and you’re
getting your listing ready, they have this feature in the native app that allows you to take
a picture of a barcode. And the barcode scanner will work out the product
you’re trying to sell and prepopulate all of the fields. I think that’s a cool user experience. I’m much more likely, as a seller, to sell something if I
don’t have to type out all of the product details. But they didn’t have this on the Web because the Web doesn’t have
a native barcode scanner. Yes, you can do it with the Canvas API, taking a picture then
reading all the pixels, but that’s gonna be a lot of work. And so, what they did is… Well, in fact, they did do that. They have a JavaScript implementation. Then they have this custom C++ one that they’re using in
their mobile app already. And then they had an
off-the-shelf open source tool that has been hardened and
written for years called ZBar. They did two experiments. The first one is that they A/B tested not having a scanner at
all on the web device, and then having a scanner. And we can see that just
by having the scanner seller completion going
from draft to a sold item increased by 30%, which really shows that that is a really
good user experience. What’s even more cool is that they then A/B tested
the JavaScript version of that barcode scanner on the Web, their own implementation, and then this open source implementation. And the open source implementation that has obviously been contributed to by many people over the
years, and is very optimized, contributed to over 50% of completions. And to me, that shows two things. One, obviously the WebAssembly performance way outperformed the JavaScript one. But two, it shows that
just using existing tools, open source ones, you don’t
have to write them yourself, to solve your problems is a really, really good thing. And WebAssembly allows us to do that now. That was a few examples and
genuine use cases in the wild. And hopefully it’s shown you a bit of the power of WebAssembly and given you some ideas
of what you could do today. But I also hope that I
showed you that WebAssembly isn’t gonna replace
JavaScript anytime soon, but it’s here to augment its flaws. Any part of your application
that you’re currently doing on the server and
that’s causing hot paths, think about that and see if you can port them to WebAssembly. Such as encoding file formats, parallelizing of data, data visualization. A lot of data visualization
that we’re doing on the Web now is really intensive and
taking a lot of data. This is a perfect use
case for WebAssembly. And the list is endless. So far we’ve looked at
WebAssembly in the browser, but what about beyond the browser? It’s the title of my talk, after all. What do I mean by this? We actually already have
JavaScript beyond the browser. Node has got support for WebAssembly now because Node is based on Chromium’s open source JavaScript engine called V8, and so when V8 got support for WebAssembly so did Node, which is awesome. That means that I can now
use WebAssembly modules inside my server-side applications and Node can benefit from
all those same benefits that the browser was doing, efficiently and safely. And it’s this safety factor
that I wanna talk a lot about. One of the problems with
running native software, especially on our servers
and in our browser, is the trust guarantees of it. It’s capable of reading
and writing to memory, and that’s extremely dangerous. Which is why we go to great efforts in our production software on our servers to make sure that our software is isolated from other users on that same server. Browsers handle this efficiently with their sandboxing model already, because of things like tabs. JavaScript that’s running in one tab can’t access the memory of the JavaScript running in another tab. And that’s an extremely,
extremely useful thing. This is why certain CDN vendors have started to use V8 as their engine to process billions of requests a second using that isolation model, so you get the trust guarantees that V8 and the browser sandbox
model has come in forever. So you can spin up a single instance of V8 and have that isolation model already, compared to, say, virtual machines that you use in AWS or GCP. The memory and CPU overhead of those you just couldn’t do on
every request inside a CDN. I actually commend this use of technology. It’s an amazing, amazing
use of technology. What’s interesting here
is that because it’s V8 it means we can also run
JavaScript and WebAssembly on the edge as well, which is awesome. We learnt that WebAssembly’s design means that we get that memory isolation and trust encapsulation for free. So maybe, actually,
WebAssembly is really useful outside of the browser. This is why Fastly’s taking
that idea a bit further, and we’re not even using V8
as our WebAssembly runtime. What if we could just run the WebAssembly directly on the server processing millions of requests a second? And so we’ve been working on exactly this. We’ve written a WebAssembly compiler that allows you to compile
any code to WebAssembly and run that on the
edge, but extremely fast. We can spin up a new
instance of WebAssembly in under 35 microseconds. And I need to always remind
myself this is not milliseconds. This is microseconds. Compared to V8, it takes around
five milliseconds to spin up and 10s of megabytes for each isolate. We can do this in 34 microseconds with only kilobytes overhead of memory. And this is possible with Lucet, which is our open source
sandboxing WebAssembly compiler. And this works by compiling
the WebAssembly module ahead of time, so not using
just-in-time compilation. So we can do that once and distribute that
everywhere on the network and then instantiate the
modules incredibly quickly, which we why we get those
trust and speed guarantees. You can go and read about it here. We’ve open sourced it. Please go and use it
in your own technology. What type of thing does this enable, having WebAssembly outside
of the browser now? It means that, for instance, I could run a GraphQL server on the edge, taking advantage of
HTTP caching within CDNs and talking to my origins. But my origins, that same code, I could have a GraphQL
server running over there. Or I could have part of the GraphQL server running on the client here,
all from the same code because it’s WebAssembly everywhere. But to do this one of the problems that
you might have thought about is that WebAssembly can only operate on numbers and bytes in memory, so it can’t actually talk to the system. It can’t make a network request. It can’t read from the file system. I’ve just said that I can run
WebAssembly on the server. How can I make a network request inside my GraphQL application
if WebAssembly can’t do that? What we need is an interface for WebAssembly to be able to talk to the hardware that it’s
running on, or the runtime, to actually make network requests. This is why Mozilla started to define what’s called the
WebAssembly System Interface. And it’s a specification
of standardized interface between the WebAssembly module and the runtime it’s talking to. That allows the compiler to say, okay, when I wanna make a network request it’s gonna compile it down to
that same interface function. And regardless of the
runtime that’s running it, they can then do this. This allows some really cool things. Imagine if I’ve got a Rust program that prints hello world. The browser WebAssembly runtime, via the WebAssembly System Interface, can decide to print that to console.log. But if it’s running on a CDN they could print that to a log stream. They could stream it to
your customer’s S3 bucket. But if that’s running just locally via something like Wasmtime, which is Mozilla’s open source
server WebAssembly runtime, you could just print that to stdout. But because we’ve got this interface now, the compiler doesn’t need
to worry about the runtime or know about the runtime. And the runtime can do
really cool things for this. Think about a file system. If the WebAssembly module
needs to open a file, the runtime could just
create a fake file system. Again, having that
security sandboxing model. So the browser could actually
give a fake file system rather than giving access to
the user’s real file system. The security benefits
from this are incredible. We’re so excited about tools like Lucet and what standards like WASI
mean for the future of the Web. Which is why at Fastly we’ve teamed up with Mozilla, Red Hat, and Intel, to form the Bytecode Alliance. That Lucet project we’ve
actually given to the alliance. We know it’s no longer our project because we think that this
WebAssembly’s way much more than just what Fastly’s doing, or what other browser vendors are doing. Go and check out the Bytecode Alliance to find out about more of these teams and some of the standards. At the beginning of the talk, we discussed about the problems of running untrusted native
code in the browser. But what we didn’t realize at the time when we were creating WebAssembly is that we’ve actually
created a universal format that we can use to run
native code safely anywhere, and extremely fast. It is the new portable
representation of any program. And for me, this is mind blowing, whether or not that’s on the browser, the edge, or the server. It’s really starting to blur the lines between what we think about
where an application can run. And it means that… What’s really cool is it means that we can run the logic for our application in the place that it should be ran. Some logic could run on
the client efficiently. Some of it should be done on the edge. But some of it should
be done on the server. And with WebAssembly, I
have this portability now. I think this is greatly
summarized by Solomon Hykes, who’s the cofounder of Docker,
in which he stated that, “If Wasm and WASI existed in 2008, “we wouldn’t have needed
to have created Docker.” That is how important it is. WebAssembly on the server is gonna be the future of computing. I know that’s a bold statement, but I am starting to think
that he might be right. All we needed was this standardized systems interface to do that, and that’s what specs like WASI are doing. Literally, at this point I could
just walk off the stage now because this tweet summarizes it for me. And I hope that I’m gonna leave you with that kind of idea in your mind. To finish, I just want to take a look at what’s left for the
future of WebAssembly. When it first shipped in
browsers, a lot of us, including myself,
thought that that was it. I can only compile C programs that only operate on streams of data and send streams of data out, because I couldn’t talk to the world. So it was only useful
for certain use cases. But that is way beyond… It could be way further from the truth. We’re only at the MVP
stage of WebAssembly. This is why I’m so excited. Tim was saying when he introduced me that, with looking at the
future future of the Web, like, this may take
five years to get here, so I don’t think that I’m
just talking fluffy nonsense. It’s gonna take a while,
but we’re gonna get there and this is how amazing it could be. The first one is which, in the Markdown example, we saw that WebAssembly’s
biggest pain points is that it can only call
the exported functions and only pass data to it in
the form of a byte array. But every programming language has got a different type system. So, a JavaScript string is different to how Rust
represents a string, which is different to how
Go represents a string. And WebAssembly has a
different understanding of how a string should
be represented in memory. But it should be possible
to ship a WebAssembly module and have it run anywhere,
without making life harder for either the person
that’s written that module or the consumer of it. So we needed this common translation layer between say the type system in JavaScript and the type system in WebAssembly. And this is where the interface
types proposal comes from. They’re still just at proposal stage, but vendors are starting to implement it. This cartoon, I have to point
out, is made by Lin Clark. If you haven’t seen
Lin’s drawings or talks, please go and watch them. She’s an amazing communicator, and boils down some
really complex problems into quite simple cartoons. And this wouldn’t be a WebAssembly talk without one of Lin’s cartoons. This means that we would no
longer need that glue code that wasm-bindgen was creating for me that I have to import my module like this. And with interface types we’re just gonna be able to
import Wasm modules directly, as if it was an ES6 module because the runtime knows
about the interface types of how to map that string to
the WebAssembly (mumbling). And for me this is like (mimics explosion) This opens up so many possibilities. The moment for me is when you realize that we can have JavaScript
dependencies like this. That my application imports a Wasm program that I got from npm, but
that itself actually calls to another JavaScript file
or TypeScript file. And another one of my
dependencies imports a Wasm one but it just so happens that
that was written in Rust, but the other one was written in C++, but me as the consumer, I didn’t even need to know that. It’s just happening, and it’s just importing
as if it was JavaScript. But people, those developers
of those specific modules have said that, okay, for
this one bit of my code I need it to run efficiently and take advantage of that optimization so that’s what I’m gonna do. But you as the consumer don’t even need to know
that that’s happening. And this could actually be happening in some of your imports already and you don’t even know that. In fact, it’s happening
for a bad reason on the Web of people trying to build cryptominers into adverts that are
running on your devices now, all in WebAssembly. But the advantage of them,
the negative advantages, are amazing. Runtimes like Node or Python’s CPython have already actually been
doing this for a while. Who here uses node-sass? Right, not that many,
there’s like four. (chuckles) Is there any more? Node-sass is written in
C, and it’s got C bindings that every time you download
or npm install something you might have seen a program
called node-gyp run up. And what that’s doing is it’s having to actually compile the C
to your instruction set, so your architecture, your x86. But we wouldn’t have to do
this with WebAssembly anymore because all we’d do as a developer is just ship the WebAssembly module and that could just run anywhere regardless of what’s consuming it. It also means, like, a data science visualization
tool that’s using Python, that same tool could now
be reused in Ruby, or Go, and these runtimes can
just import these modules. So it is this new standard portability way of running fast code. Node’s taken the first steps towards this. This is literally about two weeks ago. They’re shipping WASI support in Node. This with when V8 gets interface types mean we’re gonna have that
mind blowing eureka moment that we can just start interopping between any WebAssembly
module and JavaScript. Lastly, I don’t have enough time to go into all of the
other upcoming proposals, but here’s some of the things
that are really exciting me. First one is threads. Modern CPUs have threads. They can run multiple
operations across cores at once. And so, for us to take true advantage of the speed benefits of
WebAssembly in the browser we need to have threading support. Problem with threading support is, how it’s implemented in
browser runtimes, anyway, not the server runtimes, is that it needs support
for the shared array buffers which we had to turn
off because of Spectre. Chrome is the first people that have fortunately
turned it back on recently, and they, in Google Chrome Developer Summit last week, gave a talk that showed about the new experimental support
for WebAssembly threads. And one of the amazing stats
that came out of that is that the Google Earth team at Google compiled their Google Earth
using threaded WebAssembly, and they were able to
increase their frame rate on Google Earth by 2x, just
by turning on thread support. Which meant that their dropped frame rate dropped by 50%, which is amazing. Next we needed SIMD. This is another modern… Modern architectures have, in their core, something called SIMD which allows us to, again,
parallelize certain operations. They’re really useful for doing image or video transformation that you’re doing the same
operation on the same numbers and you wanna do it multiple times. But these two things
combined, threads and SIMD, will essentially allow us to go to speeds that were previously
impossible within a browser, and that really excites me. The most important one
is garbage collection. We need to be able to integrate with the browser’s garbage collector because when that happens we can compile things like
JavaScript to WebAssembly itself, because JavaScript’s a good
garbage collected language. The same with Go, the same with Ruby. And that’s gonna open up
a world of possibilities that I’ll talk about in just a second. And lastly, we need
better debugging support. Again, Chrome, last week, announced that you can now have much
richer debugging support in the browser for WebAssembly, so you can get stack traces
out of your Rust code that you’ve shipped to WebAssembly. Lastly, I just wanted to leave
you with this idea of what, to me, is this exciting moment of when we have those things like threads and garbage collection we can compile bits of React, say the virtual DOM diffing algorithm, in another language that takes
support of multithreading, such as Rust, and compile
just that bit of React to a WebAssembly module, ship
that inside a web worker, or load it inside a web worker so the computation is
happening off thread, but you as a consumer
just important React.js as if it was your JavaScript module. And to me, when we can
do this with frameworks we’re gonna have a dramatic
increase of performance for the Web globally without any of us really even noticing. And that, for me, is
why I’m so, so excited about the possibilities that WebAssembly in the browser holds. Let’s just recap before
Tim kicks me off the stage. Here’s some takeaways from
all of this, which is, hopefully you may have
learnt from this talk that WebAssembly isn’t gonna kill JS. It’s just here to augment
certain bits of the Web platform. It allows us to extend the Web platform using solutions that
have been battle hardened across multiple languages. We no longer are gonna
have that single ecosystem, which is amazing. And it’s not just for the browser. We can run it on the edge,
we can run it on the server. It is the new portability. And it allows us to move this
logic as close as possible to where the user needs it. What you can do today is
please go and try it out. If try out languages like Rust, as a JavaScript developer
you actually find it quite ergonomic and friendly. Profile your applications. Identify those hot paths that you need that optimization, and consider porting that bit of your application to WebAssembly, or consider finding a
tool, an off-the-shelf tool that’s already solved that problem for you in a different language. And please, just share your finding. Tell us what you’re doing. In fact, can I just have, raise a hand, who here is actually using
WebAssembly today in the browser? Wow, okay. You people I really wanna talk to. The rest of you, please go and try it out. WebAssembly is the new
standard for portability for the Web and beyond. And I think the future is really bright, and I’m really excited by it. Thank you. (audience applauding) My slides, transcripts of this talk, slides, further reading,
everything I’ve referenced, is up there if Notist has done its thing and magically loaded it. Go and check it out. – [Tim] We do have time
for a couple questions, so if you’re cool… There is a massively long
list, by the way, of questions. So, for folks, we will
not get to ask them all, so find Patrick and make him
tell you the answers later. You’re good for that, right?
– Yeah, please. – I think we all understand that WebAssembly is gonna kill JavaScript. That was clear.
– (chuckles) No. (both chuckling) – No, but I think, like… This is gonna be interesting to me, is figuring out where to use
WebAssembly versus JavaScript. Should people be… You mentioned hot parts
and stuff like that. Is it basically anything
that’s not DOM manipulation? – Well, yeah, no. The other thing, I didn’t talk enough about what JavaScript’s really good for, and you’ve just alluded to one of those, which is DOM manipulation
and talking to the DOM. There are certain things,
and just the language. Programming in such a high-level
language is really cool, and it’s really productive, which is why all of us do that. So I don’t think that you should be rewriting all of your
applications in another language. But just, I can’t stress this enough of profiling your applications and finding those hot paths. And then thinking, is there another tool that I can do this more efficiently in, or could that benefit
from parallelization, so could I run it with
multiple threads, or SIMD? Yes, we can do that
with web workers today, but not enough people are using… Who here is using web workers
in their application today? Cool, so like, not enough. And again, this is something… In fact, the talk that I was
going to give instead of this was also a talk about how we can take advantage of web workers. The most you push off the
main thread, the better. I wanna call out, again, to Das Surma. He did an amazing talk last
week at Chrome Developer Summit all about moving logic
off the main thread, and he goes into further depth
about these kind of things of what should I parallelize. JavaScript’s really good for some things. Some things, Rust or other
languages are better for. – [Tim] Does Wasm run off the main thread, or does it run on the main
thread in browsers today? How does that, the execution actual bit… – [Patrick] Either or, depending
on how you instantiate it. – Okay. How much does WebAssembly protect
you from inefficient code? If I were to write something in JavaScript just terribly, horrible performance, let’s just assume, hypothetically. And then I… (laughing) I compile it into WebAssembly. How does that process work? Does WebAssembly protect, to some extent, from the inefficiencies in the JavaScript, or is it possible to create
a Wasm that is just bad? – It’s still possible to
very much write bad code. I could write while true
and leave an infinite loop that’s running, and even on
the main thread, doing this. And that’s obviously gonna be bad. But what it means is it’s much less likely that you’ll get what’s known
as a deoptimization, or a deop. It’s really easy to move off the fast path very quickly with JavaScript by accident, and you might not even know this. I was actually talking to Stoyan at Facebook last night about this, that he’s trying… I don’t even know if I’m
allowed to talk about this. Am I allowed to talk about your tool? – Yeah.
– Yes? He’s writing some
tooling at Facebook in CI that they will then, he’s analyzing the JavaScript and he will tell, via
CI, to their developers that you have managed to
cause a JavaScript deop with the commit that you’ve just done. And we need more tooling like that. Because in JavaScript it’s so
easy to go off the fast path. To answer your question, it’s not as easy to do that with other
languages or with WebAssembly because we can do that
compilation ahead of time. – A little bit of
protection at least, okay. And then last question
before we go to lunch then. On the Wasm side of things, is there… How do we monitor the performance of the actual WebAssembly script itself? Is there any tooling that’s
being built up around that? Is there anything within
the standard that exposes a performance API through
the WebAssembly stuff? – No, and that, I didn’t go into enough. That’s one of my, that debugging
point in the last thing, the proposals that are coming. It’s something that’s
really, it’s immature. It’s really immature, and we need to create
more tooling around it. Firefox and Chrome are doing some amazing work to expose that. There are things like source
maps that are embedded inside WebAssembly via this thing called DWARF, and we’re gonna be able to visualize that if you’ve compiled the module
with that type of data. But no, we need to improve the… – Like you said, early days
still, so that’s all… – But please, go and use it, please. – Thank you, that was fantastic. – Thanks, Tim. (audience applauding)

Leave a Reply

Your email address will not be published. Required fields are marked *