javascript入门
by Daniel Simmons
丹尼尔·西蒙斯(Daniel Simmons)
WebAssembly is a brand new web technology with massive potential. It will have a significant impact on how web applications are developed in the future.
WebAssembly是一种具有巨大潜力的全新Web技术 。 这将对未来Web应用程序的开发产生重大影响。
But, sometimes, I feel like it just doesn’t want to be understood… almost in a strangely passive-aggressive kind of way.
但是,有时候,我感觉只是不想被理解……几乎以一种奇怪的被动攻击性方式。
When I look at the documentation and the handful of tutorials that are already out there, I can’t help but feel like a farmer who prayed for rain, only to drown in a flood. I technically got what I wanted… just not in the way that I’d hoped. “You want rain?! Oh, I’ll give you rain!”
当我查看已经存在的文档和少量教程时,我不禁感到自己像一个为下雨祈祷的农夫,只是淹死在洪水中。 从技术上讲,我得到了我想要的……只是没有达到我希望的方式。 “你要下雨吗?! 哦,我给你下雨 !”
This is because WebAssembly makes so many new things possible and can be implemented in so many different ways. But, it has changed so much along the way to its official MVP release in February, that when you first get started learning about it, it’s easy to drown in a sea of details.
这是因为WebAssembly使许多新事物成为可能,并且可以以许多不同的方式实现。 但是, 在2月正式发布MVP的过程中,它已经发生了很大变化,以至于您首次开始了解它时,很容易陷入细节海之中。
Continuing the rain metaphor, this article is my attempt to provide a light shower of an introduction to WebAssembly. Not the concepts or the nuts and bolts, but the actual implementation.
继续用下雨的隐喻,本文是我对WebAssembly的简介进行简短介绍的尝试。 不是概念或细节,而是实际的实现。
I’ll walk you through the steps to create and implement an extremely simple project, removing complexity wherever possible. After you’ve implemented it once, however simply, a lot of those higher level ideas are a lot easier to make sense of.
我将引导您完成创建和实施极其简单的项目的步骤,并尽可能消除复杂性。 实施了一次之后(无论多么简单),很多更高层次的想法都变得更容易理解。
Everything will be much clearer if we step back and look at a list of the steps involved in implementing WebAssembly in a project.
如果我们退后一步,看看在项目中实现WebAssembly所涉及的步骤列表,一切将变得更加清晰。
When you’re first getting started, it’s easy to look at WebAssembly and just see a big wad of options and processes. Breaking it down into discrete steps will help us get a clear picture of what’s going on:
刚开始使用WebAssembly时,很容易看到一大堆选项和流程。 将其分解为离散的步骤将有助于我们清楚地了解正在发生的事情:
Write: Write something (or use an existing project) in C, C++, or Rust
编写:用C,C ++或Rust编写某些内容(或使用现有项目)
Compile: Compile it into WebAssembly (giving you a binary .wasm file)
编译:将其编译为WebAssembly(为您提供一个.wasm二进制文件)
Include: Get that .wasm file into a project
包括:将.wasm文件放入项目中
Instantiate: Write a bunch of asynchronous JavaScript that will compile the .wasm binary and instantiate it into something that JS can play nicely with.
实例化:编写一堆异步JavaScript,它将编译.wasm二进制文件并将其实例化为JS可以很好地发挥作用的东西。
And that’s pretty much it. Granted, there are different permutations of this process, but that’s the gist of it.
就是这样。 当然,此过程有不同的排列方式,但这就是要点。
Broadly speaking, it’s not all that complicated. However, it can get extremely complicated, because most of these steps allow for widely varying degrees of complexity. In each case, I’m going to err on the side of bare-bones simplicity.
广义上讲,它并不那么复杂。 但是,它可能变得极其复杂,因为这些步骤中的大多数都允许复杂程度的变化。 在每种情况下,我都将一味简单地放在一边。
For our project, we’ll be writing a simple function in C++ (don’t worry if you’re not familiar with C++, it’ll be extremely simple). The function will return the square of a given number.
对于我们的项目,我们将用C ++编写一个简单的函数(不要担心,如果您不熟悉C ++,它将 非常简单)。 该函数将返回给定数字的平方。
Then, we’ll compile it into .wasm using an online tool (you won’t need to download or use any command line utilities). Next, we’ll instantiate it with 14 lines of JS.
然后,我们将使用在线工具将其编译为.wasm(您无需下载或使用任何命令行实用程序)。 接下来,我们将用14行JS实例化它。
When we’re done, you’ll be able to call a function written in C++ as if it were a JS function, and you’ll be amazed!
完成后,您将能够调用用C ++编写的函数,就好像它是JS函数一样,您会感到惊讶!
The sheer number of possibilities that this opens up are absolutely mind blowing.
这带来了无限的可能性,这绝对是令人震惊的。
Let’s start with our C++ code. Remember, we won’t be using a local dev environment to write or compile this.
让我们从我们的C ++代码开始。 请记住,我们不会使用本地开发环境来编写或编译该环境。
Instead, we’ll be using an online tool called WebAssembly Explorer. It’s kind of like CodePen for WebAssembly, and it allows you to compile your C or C++ code right in the browser and download a .wasm file all in one place.
相反,我们将使用一个称为WebAssembly Explorer的在线工具。 有点像用于WebAssembly的CodePen,它使您可以直接在浏览器中编译C或C ++代码,并在一个地方全部下载.wasm文件。
Once you’ve opened up WebAssembly Explorer, type this C++ code into the leftmost window:
打开WebAssembly Explorer后,请在最左侧的窗口中键入以下C ++代码:
int squarer(int num) { return num * num;}
Like I said, we’re using a really simple example here. Even if you’ve never looked at C or C++ before, it’s probably not too difficult to tell what’s going on.
就像我说的,我们在这里使用一个非常简单的示例。 即使您以前从未看过C或C ++,也可能很难说清正在发生什么。
Next, click the button that says “compile” in the red bar above your C++ code. Here’s what you’ll see:
接下来,单击C ++代码上方红色栏中的“编译”按钮。 这是您将看到的内容:
The middle column shows you a human-readable version of the .wasm binary that you’ve just created. This is called “WAT” or WebAssembly Text Format.
中间一栏显示了您刚刚创建的.wasm二进制文件的可读版本。 这称为“ WAT”或WebAssembly文本格式 。
On the right is the resultant assembly code. Pretty cool.
右边是生成的汇编代码。 很酷
I won’t go into much detail about either of these, but you do need to know at least a little bit about the WAT file in order to follow the next steps.
我不会详细介绍这两个方法,但是您需要至少了解WAT文件至少一点,以便执行后续步骤。
WAT exists because we humans generally have a hard time making sense of straight binary. It’s essentially a layer of abstraction that helps you understand and interact with your WebAssembly code.
之所以存在WAT,是因为我们人类通常很难理解正二进制。 从本质上讲,它是抽象层,可帮助您理解WebAssembly代码并与之交互。
In our case, what we want to understand is how our WebAssembly refers to the function that we just created. This because we’ll need to use that exact same name in our JS file later on to refer to it.
在我们的案例中,我们想了解的是WebAssembly如何引用我们刚刚创建的功能。 这是因为稍后我们需要在JS文件中使用完全相同的名称来引用它。
Any functions that you write in your C++ code will be available in WebAssembly as something called an “export.” We’ll talk a bit more about this later, but for now, all you need to know is that the exports are the things that you’ll be able to interact with and use.
您在C ++代码中编写的所有函数都将在WebAssembly中以称为“导出”的形式提供。 稍后我们将详细讨论这一点,但是现在,您只需要知道出口就是可以与之交互和使用的东西。
Take a look at the WAT file and look for the word “export.” You’ll see it twice: once alongside the word memory
and again alongside the word _Z7squareri
. We don’t need to know about memory
for now, but we’re definitely interested in _Z7squareri
.
查看WAT文件并查找单词“ export”。 您会看到两次:一次在单词memory
旁边,再一次在_Z7squareri
单词_Z7squareri
。 我们暂时不需要了解memory
,但是我们肯定对_Z7squareri
感兴趣。
We used the function name squarer
in our C++, but now that has somehow become _z7squareri
. This can definitely be confusing the first time you see it.
我们使用功能名称squarer
在我们的C ++,但现在已经俨然成为_z7squareri
。 第一次看到它时,肯定会造成混乱。
As far as I can tell, the “_Z7” prefix and “i” suffix are debug markers introduced by the C++ compiler. This isn’t really important to understand in depth, though. You just need to be aware that this will happen, because you need to use this exact name in your JS file in order to call your C++ function.
据我所知,“ _ Z7”前缀和“ i”后缀是C ++编译器引入的调试标记 。 不过,深入了解并不是很重要。 您只需要知道会发生这种情况,因为您需要在JS文件中使用此确切名称才能调用C ++函数。
Now just click the “download” button at the top of the purple WAT section. You’ll get the .wasm binary file. Rename it squarer.wasm
. Then create a new directory and put your squarer.wasm
file in there, along with two other files:
现在,只需单击紫色WAT部分顶部的“下载”按钮。 您将获得.wasm二进制文件。 重命名为squarer.wasm
。 然后创建一个新目录,并将您的squarer.wasm
文件以及其他两个文件放在其中:
index.html
(boilerplate)
index.html
(样板)
scripts.js
(empty for now)
scripts.js
(目前为空)
Now for the tricky part. Or, at least, the part that caused me a lot of confusion when I first started sifting through the documentation.
现在开始棘手的部分。 或者,至少,当我第一次开始浏览文档时,这引起了我很多混乱。
Although you’ll eventually be able to include .wasm modules like a regular old ES6 module (using <script type='modul
e'> ), for the time being you need to “manually” set it up. This is done by making a bunch of asynchronous calls to the WebAssembly API. There are three steps:
尽管您最终将可以包括.wasm模块,例如常规的旧ES6模块(使用<script type='modul
e'>),但是暂时需要“手动”设置它。 这是通过对WebAssembly API进行一堆异步调用来完成的。 分三个步骤:
Get your .wasm binary file into an array buffer*
将您的.wasm二进制文件放入数组缓冲区*
Compile the bytes into a WebAssembly module*
将字节编译到WebAssembly 模块中*
Instantiate* the WebAssembly module
实例化 WebAssembly模块
If all of this makes sense to you, then you can skip to the next section. But if you found yourself scratching your head a bit and want a more detailed explanation, then continue reading.
如果所有这些都对您有意义,那么您可以跳到下一部分。 但是,如果您发现自己有点挠头并想要更详细的说明,请继续阅读。
A buffer is a temporary storage place for data while it’s being moved around. Generally, this is useful when data is being received and processed at different rates.
缓冲区是数据在移动时的临时存储位置。 通常,这在以不同速率接收和处理数据时很有用。
For example, when a video is buffering, the data is being received at a rate slower than the video player can play it. One of the things that our array buffer is doing is queueing up our binary data so that it can be compiled more easily.
例如,当视频正在缓冲时,接收数据的速率低于视频播放器可以播放的速度。 数组缓冲区正在执行的操作之一是对二进制数据进行排队,以便可以更轻松地对其进行编译。
But there’s something else very important going on here. In JavaScript, an array buffer is a typed array, which is something that’s used specifically for storing binary data.
但是这里还有其他非常重要的事情。 在JavaScript中,数组缓冲区是类型化的array ,它专门用于存储二进制数据。
The fact that it is explicitly typed means that the JS engine can interpret an array buffer much faster than it can a regular array, because it already knows the data type and doesn’t have to go through the process of figuring it out.
它是显式类型的,这意味着JS引擎可以比常规数组更快地解释数组缓冲区,因为它已经知道数据类型,而不必经过弄清楚它的过程。
Once you’ve got all your binary data into an array buffer, you can compile it into a module. The WebAssembly module is, in itself, inert. It’s just the compiled binary, waiting for something to be done with it.
将所有二进制数据放入数组缓冲区后,即可将其编译为模块。 WebAssembly模块本身是惰性的。 它只是已编译的二进制文件,等待使用它完成某些操作。
You can almost think of the module like a cake recipe. The recipe is just a format for storing information about how to make a cake. If you actually want a cake, you need to create an instance of the cake described in the recipe (instantiate the cake).
您几乎可以将模块视为蛋糕食谱。 食谱只是用于存储有关如何制作蛋糕的信息的格式。 如果您确实想要蛋糕,则需要创建配方中描述的蛋糕实例(实例化蛋糕)。
You do this by following the instructions laid out in the recipe. Alternatively, you could send the recipe to someone else (a “service worker”), or you could save it and use it later (“cache” it). Both of these are much more convenient to do with a recipe, than with an actual cake.
您可以按照食谱中列出的说明进行操作。 或者,您可以将配方发送给其他人(“服务人员”),也可以保存并稍后使用(“缓存”)。 与实际蛋糕相比,这两种方法都比使用食谱方便得多。
The last thing you need to do is create an instance of your WebAssembly module, which “brings it to life” and makes it actually usable.
您需要做的最后一件事是创建WebAssembly模块的实例,该实例“使它栩栩如生”并使其实际可用。
The instance gives you access to the module’s exports (remember this from our WAT file?). This is an object that contains:
实例使您可以访问模块的出口(从WAT文件中还记得吗?)。 这是一个包含以下内容的对象:
Memory (not relevant to us, but you can read more about it here)
记忆(与我们无关,但您可以在此处了解更多信息)
Here’s the code that accomplishes all of the steps we just went over (this goes into your scripts.js
file):
这是完成我们刚刚完成的所有步骤的代码(该代码进入了scripts.js
文件):
The loadWebAssembly()
function fetches your .wasm file and then performs the operations mentioned above. Then it returns a new instance of your WebAssembly module.
loadWebAssembly()
函数获取您的.wasm文件,然后执行上述操作。 然后,它返回WebAssembly模块的新实例。
Our C++ function (remember it’s referred to by the funky name that we mentioned before: _z7squareri
) lives in the exports property of our instance. You can see it being assigned to the global variable squarer
on line 12. Now we can use squarer()
as a regular JavaScript function!
我们的C ++函数(请记住,它由我们之前提到的时髦名称_z7squareri
)位于我们实例的exports属性中。 您可以在第12行看到它被分配给全局变量squarer
功能。现在,我们可以将squarer()
用作常规JavaScript函数!
Once you put this into your scripts.js
file and hit save, you can pull it up on localhost and you should see the “Finished compiling…” message in the console.
将其放入scripts.js
文件并点击保存后,就可以在localhost上将其拉出,并且应该在控制台中看到“ Finished compiling…”消息。
Now, just call your function and pass in an argument from the console. Try something like squarer(9)
. Hit return and you’ll see 81
. It works! You’re calling a function written in C++!
现在,只需调用您的函数并从控制台传递一个参数即可。 尝试使用squarer(9)
类的东西。 按回车键,您将看到81
。 有用! 您正在调用用C ++编写的函数!
You can just imagine all of the things that this makes possible.
您可以想象所有可能实现的所有事情。
For one, JavaScript is no longer your only option for “doing things” in the browser. That is absolutely huge.
首先,JavaScript不再是浏览器中“做事”的唯一选择。 那绝对是巨大的。
Then there’s the performance improvements, since WebAssembly, unlike JS, runs at near-native speed.
然后是性能的提高,因为WebAssembly与JS不同,其运行速度接近于本地。
And then there’s all the legacy code that’s now at your disposal. C and C++ have been around for a long time, and in that time, a lot of brilliant people have created some amazing open-source projects with it. Projects that can now be integrated into websites or apps.
然后,所有遗留代码现在可供您使用。 C和C ++已经存在很长时间了,那时,许多才华横溢的人使用它创建了一些了不起的开源项目。 现在可以集成到网站或应用程序中的项目。
From here, you can write more complex C, C++, or Rust code, or even adapt an existing project, and “wasm-it” into a web project.
从这里,您可以编写更复杂的C,C ++或Rust代码,甚至改编现有项目,然后将“ wasm-it”集成到Web项目中。
One caveat, however, is that if you want to create functions that accept arguments or return values that are not numbers, then things start to get a bit more complicated. That’s when you’ll need to learn a bit more about the memory attribute of the .wasm instance’s exports.
但是,有一点需要注意的是,如果您要创建接受参数或返回非数字值的函数,那么事情就会变得更加复杂。 到那时,您需要了解有关.wasm实例的导出的内存属性的更多信息。
This project is available on GitHub if you’d just like to clone a working copy in addition to following along with the article.
如果您只想克隆一个工作副本,那么除了在本文中关注以下内容之外,该项目还可以在GitHub上使用。
javascript入门