WebAssembly的发展历程相对较短,但影响深远。WebAssembly 于 2015 年首次发布,先驱技术是来自Mozilla的asm.js和Google Native Client,最初的实现是基于asm.js的功能集。自2017年3月由WebAssembly创造的MVP的预览版发布以来,WebAssembly发展迅速,目前已经部署到了所有主流浏览器。到了2019年,WebAssembly 1.0成为了W3C推荐的标准,这打破了之前仅用JavaScript来进行Web开发的局面。那么什么是WebAssembly? 这篇文章让你从多方面了解WebAssembly这一技术。

WebAssembly是什么?

WebAssembly(简称Wasm)是一种新型的、可以在现代Web浏览器中运行的代码。这是一种低级类汇编语言,其二进制格式紧凑,为诸如 C、C++和 Rust 等低级源语言提供一个高效的编译目标,以便它们可以在Web上运行。开发者通过自选语言编写代码,然后将其编译为WebAssembly字节码进行运行。字节码在客户端(通常是Web浏览器)上运行,在那里它被编译为可执行机器码并以接近原生的速度执行。

由于Wasm提供给浏览器的是以二进制格式编译的代码,节省了下载和解析JavaScript代码时间,使代码执行效率更高。此外,WASM提供了开发者手动管理内存的选项,以及可以直接访问内存的特性,从而提升了运行效率。WebAssembly不仅具有高效的解析和执行能力,还有着硬件和操作系统无关的低级虚拟机模型,提供了安全的运行环境。当前,WASM可以兼容主流的Web浏览器,例如Chrome、Edge、Firefox、Opera和Safari。

WASM被设计为与JavaScript协同工作,以此实现Web平台上的高性能应用。综合来看,WASM在Web平台上表现出近乎原生的开发速度,充分凸显了WebAssembly的性能与功能,以及JavaScript的表现力与灵活性,使得客户端应用可以轻松地在Web上运行。

WebAssembly的关键原理

在了解如何编译C语言为WASM的步骤之前,你需要先了解几个关键原理。

模块(Module): 表示一个已经被浏览器编译为可执行机器码的 WebAssembly 二进制代码。模块中包含一系列的函数和数据(例如,全局变量和初始化的内存)。模块是无状态的,能够像ES2015 的模块一样声明导入和导出。

内存(Memory): WebAssembly使用一种名为线性内存的数据结构来表示内存。线性内存是一个连续的字节块,其大小总是一页(64 KiB)的倍数。WebAssembly代码可以直接读取和写入这些字节。

表格(Table): 可调整大小的类似于数组的结构,包含引用(例如函数),出于安全和可移植性考虑,这些引用不能以原始字节形式存储在内存中。

实例(Instance): 一个已经与运行时使用的所有状态配对的模块,包括内存、表和导入值集。一个实例就像一个 ES 模块,它被加载到一个特定的整体中,并带有一组特定的导入值。

一个WebAssembly模块定义了一系列的函数、全局变量、内存和表格,它们通过与特定的导入和导出的值结合,可以被实例化为一个运行的应用。而内存和表格也可以被实例化为运行的应用,它们的值随着应用的执行而改变。

编译C/C++为Wasm的操作步骤

在示例如何用C语言编译为 Wasm之前,你需要满足一个前提条件 —— 获取 Emscripten SDK来配置安装环境。使用 Emscripten 编译主要适用于两个场景,下面分别来了解一下具体的操作步骤。

创建 HTML 和 JavaScript

你可以用 C 语言编写一个程序,使用 Emscripten SDK 将该程序编译成 WebAssembly,然后创建一个 HTML 文件,在网络服务器上加载并运行 WebAssembly 代码。

  1. 首先我们需要一个例子来编译。复制以下简单的 C 示例,并将其保存在本地目录并命名为 hello.c 的文件中:
#include <stdio.h>

int main() {
printf("Hello World\n");
return 0;
}
  1. 现在,使用进入 Emscripten 编译器环境时使用的终端窗口,导航到与 hello.c 文件相同的目录,然后运行以下命令:

emcc hello.c -o hello.html
  1. 我们通过命令传递的选项如下:

-o hello.html —— 这指定我们希望Emscripten生成一个HTML页面来运行我们的代码(以及要使用的文件名),以及Wasm模块和JavaScript粘合代码来编译和实例化Wasm,使其可以在Web环境中使用。

  1. 在这个时候,你的源代码目录中应该有:
  • 二进制的Wasm模块代码(hello.wasm
  • 一个包含粘合代码的JavaScript文件,用于在原生C函数和JavaScript/Wasm之间进行转换(hello.js
  • 一个HTML文件,用于加载、编译和实例化你的Wasm代码,并在浏览器中显示其输出(hello.html
  1. 现在,在支持 WebAssembly 的浏览器中加载生成的hello.html来运行示例。Firefox 52、Chrome 57、Edge 57 和 Opera 44 默认启用了 WebAssembly。
  2. 如果运行顺利,您应该会在网页上以及浏览器的 JavaScript 控制台上看到 Emscripten 控制台中的"Hello world"输出。

使用自定义 HTML 模板

  1. 首先,在新目录中,将以下 C 代码保存在名为hello2.c的文件中:

#include <stdio.h>

int main() {
printf("Hello World\n");
return 0;
}
  1. 在 emsdk 存储库中搜索文档shell_minimal.html。将其复制到之前新目录中名为html_template的子目录中。
  2. 现在导航到您的新目录(同样,在您的 Emscripten 编译器环境终端窗口中),并运行以下命令:

emcc -o hello2.html hello2.c -O3 --shell-file html_template/shell_minimal.html
  1. 这次我们传递的选项略有不同:
  • 我们已经指定了-o hello2.html,这意味着编译器仍将输出 JavaScript 粘合代码 和.html
  • 我们指定了-O3,用于优化代码。Emcc 与任何其他 C 编译器一样具有优化级别,包括:(-O0无优化)、-O1-O2-Os-Oz-Og-O3-O3是发布版本的良好设置。
  • 我们还指定了--shell-file html_template/shell_minimal.html —— 这提供了您要用来创建将运行示例的 HTML 的 HTML 模板的路径。
  1. 现在让我们运行这个例子。上面的命令将生成hello2.html,其内容与模板大致相同,并添加了一些粘合代码来加载生成的 Wasm、运行它等。在浏览器中打开它,您将看到与上一个示例大致相同的输出。

调用 C 语言定义的自定义函数

如果你在 C 代码中定义了一个函数,而又想根据需要从 JavaScript 中调用该函数,那么您可以使用Emscripten ccall()函数和EMSCRIPTEN_KEEPALIVE声明(该声明会将您的函数添加到导出函数列表中)来实现这一目的。

  1. 首先,在新目录中将以下代码保存为hello3.c.默认情况下,Emscripten 生成的代码只会调用 main() 函数,其他的函数将被视为无用代码。在一个函数名之前添加 EMSCRIPTEN_KEEPALIVE 能够防止这样的事情发生。你需要导入 emscripten.h 库来使用 EMSCRIPTEN_KEEPALIVE
#include <stdio.h>
#include <emscripten/emscripten.h> int main() {
printf("Hello World\n");
return 0;
} #ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endif EXTERN EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char ** argv) {
printf("MyFunction Called\n");
}
  1. 现在,为了方便起见,将包含 {{{ SCRIPT }}} 内容的 html_template/shell_minimal.html 也添加到这个新目录中(在实际开发环境中,显然应将其放在中心位置)。
  2. 现在让我们再次运行编译步骤。在最新目录下(在 Emscripten 编译器环境的终端窗口中),用以下命令编译 C 代码。请注意,我们需要使用 NO_EXIT_RUNTIME 进行编译:否则,当 main() 退出时,运行时将被关闭,并且调用编译后的代码将无效。这对于正确的 C 语言模拟来说非常必要:例如,确保调用 atexit() 函数。
emcc -o hello3.html hello3.c --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']"
  1. 如果你在浏览器中在此加载实例,你将看到和之前相同的结果。
  2. 现在我们需要运行新的 myFunction() JavaScript 函数。首先,在文本编辑器中打开hello3.html文档。
  3. 添加一个<button>元素,如下所示,就在第一个 <script type='text/javascript'> 开始标签的上方。
<button id="mybutton">Run myFunction</button>
  1. 现在在第一个 <script> 元素末尾添加以下代码:
document.getElementById("mybutton").addEventListener("click", () => {
alert("check console");
const result = Module.ccall(
"myFunction", // name of C function
null, // return type
null, // argument types
null, // arguments
);
});

结尾

目前,WebAssembly已经逐渐被用在很多Web应用中,包括复杂的图形处理和游戏开发,AI和机器学习,音频和视频处理等等。随着技术的发展,WebAssembly的应用领域和影响力将会越来越大。

我们最近发布的ComPDFKit Web Demo应用了最新的WebAssembly技术,为用户提供一个纯前端的方案,即在客户端上运行,而无需依赖Server端处理PDF文档。使用这个方案,你的PDF渲染速度更快,并且在不同平台渲染的效果一致。欢迎联系我们获取更多信息并试用我们的Demo.

WebAssembly照亮了 Web端软件的未来的更多相关文章

  1. 从开源模型、框架到自研,声网 Web 端虚拟背景算法正式发布

    根据研究发现,在平均 38 分钟的视频会议里面,大概会有 13 分钟左右的时间用于处理和干扰相关的事情.同时研究也表明在参加在线会议的时候,人们更加倾向于语音会议,其中一个关键原因就是大家不希望个人隐 ...

  2. 力软信息化系统快速开发框架 web端+winform端

    力软信息化系统快速开发框架是一套集权限管理+快速开发+动态接口+通用组件+动态UI于一体的全新.net信息化快速开发框架.力软信息化系统快速开发框架的使用,大大地缩短了开发周期,提高了软件质量,同时也 ...

  3. Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

    1. 前言 Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Serve ...

  4. 新手入门:史上最全Web端即时通讯技术原理详解

    前言 有关IM(InstantMessaging)聊天应用(如:微信,QQ).消息推送技术(如:现今移动端APP标配的消息推送模块)等即时通讯应用场景下,大多数都是桌面应用程序或者native应用较为 ...

  5. Asp.net SignalR 实现服务端消息推送到Web端

              之前的文章介绍过Asp.net SignalR,  ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.  今天我 ...

  6. Web端即时通讯技术原理详解

    前言 有关IM(InstantMessaging)聊天应用(如:微信,QQ).消息推送技术(如:现今移动端APP标配的消息推送模块)等即时通讯应用场景下,大多数都是桌面应用程序或者native应用较为 ...

  7. Web端测试和移动端测试的区别

    1.记录bug 在Web端可以通过系统自带的截图和QQ截图等方式来截取bug的图片,对于错误的地方可以用工具自带的标识来重点标记. 对于移动端设备可以用手机自带的截图工具来截图然后传到电脑上,个人一般 ...

  8. Comet技术详解:基于HTTP长连接的Web端实时通信技术

    前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Ser ...

  9. web端测试和移动端测试的区别小记

    转:http://qa.blog.163.com/blog/static/19014700220157128345318/ 之前一直参与web端的测试,最近一个项目加入了移动端,本人有幸参与了移动端的 ...

  10. 新发现:AirDroid(用Web端控制自己的手机发信息)

    http://web.airdroid.com/ 好多功能呀,有空研究研究 http://jingyan.baidu.com/article/b24f6c82cd4ade86bfe5daf3.html ...

随机推荐

  1. Kafka 社区KIP-382中文译文(MirrorMaker2/集群复制/高可用/灾难恢复)

    译者:对于Kafka高可用的课题,我想每个公司都有自己的方案及思考,这是一个仁者见仁智者见智的命题,而社区给出了一个较大的特性,即MirrorMaker 2.0,不论是准备做高可用还是单纯的数据备份, ...

  2. Linux-关机重启和注销

  3. 【Mysql系列】(二)日志系统:一条更新语句是如何执行的

    有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top 这篇文章是从Github ReadMe拷贝的,内容实践下载是没问题的,能够正 ...

  4. parquet极简学习

    parquet极简学习 摘要 parquet的概念: Parquet文件是一种列式存储文件格式,广泛应用于大数据处理框架, 如Apache Hadoop和Apache Spark. 它通过将数据组织成 ...

  5. [转帖]【P1】Jmeter 准备工作

    文章目录 一.Jmeter 介绍 1.1.Jmeter 有什么样功能 1.2.Jmeter 与 LoadRunner 比较 1.3.常用性能测试工具 1.4.性能测试工具如何选型 1.5.学习 Jme ...

  6. [转帖]Kafka 核心技术与实战学习笔记(六)kafka线上集群部署方案

    一.操作系统-Linux Kafka是JVM系的大数据框架 kafka由Scala语言和Java语言编写而成,编译之后的源代码就是普通的".class"文件 使用Linux kaf ...

  7. [转帖]kubelet 原理解析六: 垃圾回收

    https://segmentfault.com/a/1190000022163856 概述 在k8s中节点会通过docker pull机制获取外部的镜像,那么什么时候清除镜像呢?k8s运行的容器又是 ...

  8. Spring 应用合并之路(二):峰回路转,柳暗花明 | 京东云技术团队

    书接上文,前面在 Spring 应用合并之路(一):摸石头过河 介绍了几种不成功的经验,下面继续折腾- 四.仓库合并,独立容器 在经历了上面的尝试,在同事为啥不搞两个独立的容器提醒下,决定抛开 Spr ...

  9. Ant Design Vue 单文件上传Upload

    单文件上传 <a-upload name="file" :beforeUpload="beforeUpload" :multiple="fals ...

  10. file文件转为base64

    场景描述 在工作中,我们经常需要进行文件上传. 比如在进行图片上传的时候, 我们需要将上传的图片展示出来. 这个时候我们就需要将file文件转化为base64. 将file文件转化为base64 // ...