webassembly
有一种新武器 与JavaScript的大战 努力让开发人员选择自己喜欢的编程风格,同时提高性能和生产率。 该武器是WebAssembly ,它将彻底改变客户端的Web开发。
WebAssembly或wasm是浏览器内客户端脚本的低级字节码格式 。 如果要编写用于编程语言的编译器,则一种选择是针对平台(例如JVM或.NET),然后将语言编译为目标字节码。 WebAssembly担当着相同的角色,因此,当您编译为WebAssembly时,将使您的软件可用于支持该软件的所有平台,即所有浏览器。
实际上,WebAssembly是由浏览器的开发人员在现有JavaScript引擎的支持下实现的。 本质上,它旨在代替JavaScript作为Web上编译器和编译器的目标。 例如,现在,开发人员可以将TypeScript编译为WebAssembly,而不必将TypeScript编译为JavaScript。 简而言之,它不是一个新的虚拟机,它是每个浏览器中包含的同一JavaScript VM的新格式。 这样就可以在不使用JavaScript的情况下利用现有JavaScript基础结构。
最低可行产品的设计已于2017年3月完成,现在每种主流浏览器都有相应的实现方案 。
为什么重要?
首先,新的WebAssembly格式在解析性能方面有望显着提高
WebAssembly所考虑的那种二进制格式可以比JavaScript解析的速度快得多(实验显示快20倍以上)。 在移动设备上,大型的编译代码仅需20到40秒即可解析,因此本机解码(尤其是与其他技术结合使用,例如流媒体提供比gzip更好的压缩效果)对于提供良好的冷负载用户体验至关重要。
请注意,我们在谈论的是解析性能,不一定是执行性能。 因为在许多情况下,它将在现有JavaScript引擎上运行。 但是,仅解析性能的这种提高将允许安装以前无法开发的Web软件。 例如: 虚拟机,虚拟现实,图像识别等 。
最初的生产用户可能会是游戏引擎开发人员,因为他们一直在寻找最佳性能。 在WebAssembly之前,他们所希望的最好的方法是asm.js(一种简化JavaScript,针对速度进行了优化),这是一项很酷的技术,但实际上并不能用于许多游戏。 我记得尝试过虚幻技术公司的著名演示Epic Citadel(现已离线)。 实际上运行起来很顺利,但是下载和解析代码大约花了15分钟,对于快速游戏而言 ,这显然不够好。
实际上, Autodesk计划为其Stingray游戏引擎支持WebAssembly,而Unity 游戏引擎的创建者Unity Technologies 早在2015年就开始尝试WebAssembly 。 Rust开发人员也已经在努力支持WebAssembly在Web上运行Rust代码 。
它能为您做什么
在更大的情况下,WebAssembly的到来意味着您不再被迫将JavaScript用于Web,因为它是唯一在浏览器中运行的东西 。 JavaScript的声誉很差,但实际上对于设计用途而言,它是一门好语言:快速编写小型脚本。 问题是,当前您被迫用于在Web上运行所需的所有其他功能,而这对于许多大型项目来说都是一个问题。
的确,您可以使用更好JavaScript版本(例如TypeScript),甚至可以使用新的语言(例如Kotlin) 。 但是,最后它们都必须编译为JavaScript。 反过来,这给JavaScript开发人员带来了问题,这些问题实际上必须支持所有方案和所有编程样式。 WebAssembly将改变这种状况,并使每个人都可以专注于自己可以做得更好的事情。
这还不是全部: 可以将WebAssembly移植到其他平台 。 这意味着,如果您使用可编译为WebAssembly的语言编写软件, 则可以在.NET上运行它 。 它允许重用Web上已经存在JavaScript基础结构这一事实意味着您可以在生产中使用它。
但是,这不是唯一的选择。 您可以根据需要创建自己的特定实现。 您可以为您的语言创建优化的编译器。 您可以从头开始创建它,也可以将WebAssembly支持添加到现有编译器中。 这样,您就可以利用所有其他WebAssembly模块。
例如,您可以为公司内部使用的DSL创建一个WebAssembly编译器,并使其在客户端的Web上运行,而无需使用Oracle Java Plug-in或Adobe Flash之类的自定义插件。
这个怎么运作
WebAssembly的基本原则是与现有JavaScript世界很好地集成。 范围从技术方面(例如可互操作性和共享安全策略(起源))到工具集成(例如支持Web浏览器的“查看源”功能)。
为了实现此目标,WebAssembly为工具和人类读者定义了二进制格式和等效文本格式。 从技术上讲,文本格式使用S-expressions ,因此它将类似于以下内容。
(func (param i32) (local f64)
get_local 0
get_local 1)
但是,这些工具可能会显示与此表示形式更相似的内容(来自文档的示例)。
C ++ | 二元 | 文本 |
---|---|---|
|
|
|
您可能想知道为什么以C ++为例。 这是因为WebAssembly的初始版本(MVP)的目标是支持C / C ++。 其他语言将稍后发布。 目前,它们正在开发中。 选择该文件是出于两个技术和实践原因:
- WebAssembly的MVP不支持垃圾回收( 正在进行中 )
- 从C / C ++到WebAssembly编译器的实现可以依赖于即时可用且经过测试的工具,例如LLVM(最常用的一组编译器工具之一)
WebAssembly开发人员使用LLVM来减少获得有效产品所需的工作量。 此外,这使他们可以轻松地与其他与LLVM配合使用的工具集成,例如Emscripten。
使用MVP,真正的程序员可以进行测试和使用,从而可以相应地改进WebAssembly。
Web组装工具
目前,官方WebAssembly工具只能将C / C ++编译为WebAssembly,尽管其他开发人员已经开始着手为其他语言和平台添加支持(之前我们提到过.NET和Rust)。 但是,即使使用官方工具,您也可以通过两种方式将其用于Web开发:
- 以文本格式编写WebAssembly,然后使用提供的工具将其转换为二进制文件
- 使用基于这些工具的第三方工具
首选不是真正通用的实用工具,但是如果您想了解这种格式或开始将其集成到自己的工具中,则可以采用这种方法。 实际上有两个工具包: WebAssembly Binary Toolkit和Binaryen 。
WABT包括用于开发和/或用于WebAssembly的工具中的工具:
- 它完全支持格式规范
- 它可以从/转换为文本格式
- 它包括一个口译员
简而言之,它可以确保以干净方便的方式访问WebAssembly格式的数据,以便您可以使用它。
另一方面, Binaryen是一种工业实力工具箱,旨在用于编译器基础结构:
- 它可以与WebAssembly代码或供编译器使用的控制流程图形式一起使用
- 它通过许多遍优化代码,包括标准优化和WebAssembly的特定优化
- 它可以从asm.js(JavaScript的一个子集),Rust MIR(Rust的中间语言)和LLVM进行编译
因此,该工具包已准备好集成到您的生产后端中。
本质上,两者都允许您创建用于操纵WebAssembly的工具,但是WABT是专为在开发过程中使用的工具(例如,静态分析)而设计的,而Binaryen是用于创建生产WebAssembly(例如,编译器)的。
这些工具非常适合开发工具和与编译器相关的产品的人:它们既提供开发工具,又提供即用型生产工具。 但是,对于普通开发人员而言,它们并不理想,因为对于他们而言,这是一种更简单的方法。
如果您需要构建此类工具,那么还有第二种选择:从头开始构建所有内容。 如果您需要使用自己的语言的自定义编译器或解释器,需要最佳性能或轻量级的工具,则可以采用这种方法。 由于我们已经使用过WebAssembly,因此我们创建了一个库来帮助您(和我们)使用WebAssembly: WasmCompilerKit 。 基本上,它是一个Kotlin库,可用于加载WASM文件,对其进行修改并生成它们。 鉴于它是用Kotlin编写的,因此您也可以在Java和Scala中使用它。 我们正在考虑在也针对JavaScript的多平台Kotlin项目中对其进行转换。
使用WebAssembly
如果您只是对使用WebAssembly感兴趣的开发人员,建议的开始方式是使用Emscripten(SDK) 。 Emscripten是已经用于在asm.js中编译C / C ++的工具链,asm.js是JavaScript的子集,其目的与WebAssembly相似。 使用Emscripten,您可以更轻松地使用前面提到的Binaryen并将其与自己的链集成在一起。
安装Emscripten或从源代码编译它之后,必须安装binaryen。
# these commands should be executed inside the emsdk folder
# on Linux or Mac OS X
# this step might take a while
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
# on Windows
# this step might take a while
# if you are using Visual Studio 2017, append --vs2017
emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
然后,每次启动以下命令时,要激活编译环境并确保设置了正确的路径和变量。
# the command should be executed inside the emsdk folder
# on Linux or Mac OS X
source ./emsdk_env.sh --build=Release
# on Windows
emsdk_env.bat --build=Release
最后,您可以编写代码。
#include <stdio.h>
int factorial(int n) {
if (n == 0)
return 1;
else
return n * factorial(n-1);
}
int main(int argc, char ** argv) {
int number = 5;
int fact = factorial(number);
printf("The factorial of %d is %d", number, fact);
}
然后编译为WebAssembly并在浏览器中查看。
emcc WebAssemblyExample.c -s WASM=1 -o WebAssemblyExample.html
# launch the local web server included with emscripten
emrun --no_browser --port 8080 .
第一个命令将生成三个文件:WASM模块,显示正在运行的代码HTML文件和设置模块并负责运行该模块的所有JS文件。 WASM=1
指示Emscripten我们要生成WASM模块,而不是asm.js文件。
您也可以使用--shell-file
选项在自定义模板中输出代码。 Emscripten SDK安装在此位置(esmdk-folder)/emscripten/incoming/src/shell_minimal.html
包含基本模板。 在您的项目中复制该文件并适应您的需求(例如,添加其余的JS代码)。
# We renamed it WebAssemblyTemplate.html
emcc -o WebAssemblyExample.html WebAssemblyExample.c -O3 -s WASM=1 --shell-file WebAssemblyTemplate.html
您也可以直接输出JS文件,但目前不建议这样做。 那是因为您需要代码来处理诸如内存分配,内存泄漏等底层问题。
最终目标是使加载WebAssembly模块变得容易,就像使用<script type='module'>
HTML代码加载JavaScript代码一样,但我们还没有完成。
C和JavaScript之间的互操作性
C和JavaScript之间的互操作性是Emscripten的问题。 您要做的第一件事是包括emscripten的头文件。
#include <emscripten.h>
调用JavaScript的更简单方法是简单地调用函数emscripten_run_script
:
// it is equivalent to call eval() in JavaScript
emscripten_run_script("alert('hello')");
而是从JavaScript调用C函数稍微复杂一些。 首先,必须从C / C ++代码中使它可用,因为默认情况下,Emscripten使所有C函数(主要函数除外)都不可用。 因此,必须将修饰符EMSCRIPTEN_KEEP_ALIVE
添加到要在JavaScript中使用的所有函数。
int EMSCRIPTEN_KEEPALIVE factorial(int n) {
if (n == 0)
return 1;
else
return n * factorial(n-1);
}
如果您使用C ++编写,请记住将要提供的任何函数放在extern 'C'
块中,以避免C ++破坏函数的名称(这是C ++所做的,这不是WebAssembly或Emscripten错误) 。
其次,您必须使用选项NO_EXIT_RUNTIME
编译WebAssembly模块,这样可以避免在主函数退出时关闭运行时,这将导致无法从JavaScript调用C代码。
emcc -o WebAssemblyExample.html WebAssemblyExample.c -O3 -s WASM=1 -s NO_EXIT_RUNTIME=1 --shell-file WebAssemblyTemplate.html
第三,您不能直接调用C函数,但必须使用以下语法。
Module.ccall('factorial', // name of C function
'number', // return type
['number'], // argument types
[4] // arguments
);
类型可以是以下三种之一 :数字,字符串和数组。
如果需要在JavaScript代码中多次使用该函数,则可以使用cwrap
函数将其包装。
factorial = Module.cwrap('factorial', 'number', ['number'])
factorial(4);
您可以在控制台中轻松尝试。
摘要
我们已经看到了WebAssembly的简短介绍:它是什么,为什么要关心以及如何使用它。 这将成为Web进一步发展的绝佳平台:它将使Web开发更加轻松和高效。
它的开发得到了Mozilla,Microsoft,Google和Apple的支持。 对工具的关注是WebAssembly重要性的另一证明:它将快速改变Web。
您可以立即使用WebAssembly,并在MDN网站上查看更深入的文档。 如果您想了解有关格式的更多详细信息,可以在官方网站上阅读它们。 您也可以查看Emscripten文档,以了解与JavaScript和C / C ++代码之间的互操作性有关的问题。
翻译自: https://www.javacodegeeks.com/2017/12/introduction-webassembly-care.html
webassembly