揭开WebAssembly的神秘面纱:初学者需要知道的

WebAssembly(Wasm)是一种二进制格式,旨在提高web应用程序的性能。它的创建是为了解决JavaScript的局限性,JavaScript是一种解释语言,可能会导致性能下降和页面加载时间延长。

使用WebAssembly,开发人员可以将代码编译为低级别的二进制格式,现代web浏览器可以以接近原生速度执行该格式。这对于需要密集计算或需要处理大量数据的应用程序尤其有用。

将代码编译到Wasm需要一些编程语言和所用工具的知识,以及对WebAssembly格式及其如何与浏览器环境交互的理解。然而,提高性能和安全性的好处使它成为许多开发人员的一项值得努力的工作。

在本文中,我们将探讨WebAssembly的基础知识,包括它如何与web浏览器协同工作,如何将代码编译为Wasm,以及编写安全WebAssembly代码的最佳实践。

我们还将讨论基准测试和示例,以说明与传统web技术相比,使用WebAssembly的性能优势。你将了解如何使用WebAssembly创建更快、更高效、更安全的web应用程序。

使用WebAssembly的好处

如前所述,由于其高效的二进制格式和更简单的指令集,与JavaScript相比,WebAssembly提供了更快的执行时间和改进的性能。它使开发人员能够使用其他语言来创建web应用程序,如C++、Rust等。

Wasm还为在网络上运行代码提供了一个更安全的环境。除了性能之外,在web开发中使用它还有其他几个好处:

——便携性。Wasm被设计为与语言无关,可以与多种编程语言一起使用,使开发人员能够用他们喜欢的语言编写代码,并将其编译到WebAssembly中以在网络上使用。

——安全。它为执行代码提供了一个沙盒环境,使其比直接在浏览器中执行不受信任的代码更安全。

——互操作性。Wasm模块可以很容易地与JavaScript集成,允许开发人员在使用新的WebAssembly模块的同时使用现有的库和框架。

——可用性。它可以用于将用原生语言编写的应用程序带到网络上,使用户更容易访问这些应用程序,而无需安装其他软件。

WebAssembly可以用两种形式表示:二进制格式和文本格式。

二进制格式是Wasm的原生格式,由表示程序指令和数据的字节序列组成。这种二进制格式被设计成紧凑、高效并且易于被机器解析。二进制格式也是当Wasm程序加载到网页中时通常通过网络传输的形式。

另一方面,WebAssembly的文本表示是一种更易于阅读的形式,类似于汇编语言。与二进制格式相比,文本格式设计得更可读,更易于编写和调试。文本格式由一系列指令组成,每个指令都使用助记符及其操作数表示,并且可以使用WebAssembly编译器将其转换为二进制格式。

文本格式对于编写和调试Wasm程序非常有用,因为它允许开发人员更容易地阅读和理解程序的指令。此外,文本格式可用于用高级编程语言编写程序,然后将其编译为WebAssembly,这有助于简化编写和优化Wasm程序的过程。

什么是WebAssembly指令集?

WebAssembly有一个简单的、基于堆栈的指令集,其设计易于优化性能。它支持整数和浮点数等基本类型,以及向量和表等更复杂的数据结构。

Wasm指令集由少量低级指令组成,这些指令可用于构建更复杂的程序。这些指令可用于操作整数、浮点和内存地址等数据类型,并执行分支和循环等控制流操作。

WebAssembly指令的一些示例包括

——i32.add:将两个32位整数相加。

——f64.mul:将两个64位浮点数相乘。

——i32.load:从内存中加载一个32位整数。

——i32.store:将一个32位整数存储到内存中。

——br_if:如果条件为true,则分支到给定的标签。

WebAssembly指令在基于堆栈的虚拟机上操作,在执行指令时,值被推送到堆栈上或从堆栈中弹出。例如,i32.add指令从堆栈中弹出两个32位整数,将它们相加,然后将结果推回到堆栈中。

这一点意义重大,因为它提高了执行的效率和简单性。

基于堆栈的架构允许指令的有效执行。由于值被推送到堆栈上,因此指令可以很容易地访问最上面的值并对其进行操作,而不需要显式寻址或复杂的内存操作。这减少了执行计算所需的指令数量,从而加快了执行速度。

此外,基于堆栈的模型简化了虚拟机的设计和实现。指令可以设计为直接与堆栈上的值一起工作,从而消除了对复杂寄存器管理或内存寻址模式的需要。这种简单性导致了一个更紧凑、更易于理解的指令集。

WebAssembly指令集中的少量指令使其易于优化和安全。因为指令是低级的,所以可以很容易地将它们翻译成机器代码,从而使Wasm程序快速高效。

此外,固定指令集意味着这些程序不容易出现更复杂的指令集中可能出现的相同类型的安全漏洞。

Wasm如何与浏览器一起工作?

WebAssembly代码是在浏览器的沙盒环境中加载和执行的。它通常使用fetch()API异步加载,然后使用WebAssembly API编译和执行。

Wasm可以与web浏览器协同工作,在客户端环境中提供高效、安全的代码执行。它的代码可以使用JavaScript在网页中加载和执行,并且可以与文档对象模型(DOM)和其他web API交互。

当网页加载WebAssembly模块时,浏览器会下载模块的二进制文件,并使用名为WebAssembly Runtime的虚拟机将其编译为机器代码。WebAssembly Runtime集成到浏览器的JavaScript引擎中,并将Wasm代码转换为可由浏览器处理器执行的机器代码。

一旦加载并编译了WebAssembly模块,浏览器就可以执行其功能并与数据交互。Wasm代码还可以使用JavaScript互操作调用JavaScript函数和访问浏览器API,这允许WebAssembly和JavaScript之间的无缝通信。

WebAssembly的高效执行可以为web应用程序提供显著的性能优势,尤其是在数据处理或科学计算等计算密集型任务中。此外,Wasm的安全模型强制执行严格的内存隔离和控制流完整性,可以提高web应用程序的安全性并降低安全漏洞的风险。

如何将代码编译到WebAssembly

要将代码编译到WebAssembly,开发人员可以使用针对Wasm二进制格式的编译器,如Clang或Emscripten。

开发人员还可以使用内置支持WebAssembly的语言,如Rust或AssemblyScript。

要将代码编译到WebAssembly,需要一个支持生成Wasm输出的编译器。以下是一些一般步骤:

1. 选择一种具有能够生成WebAssembly输出的编译器的编程语言。一些支持WebAssembly的流行语言包括C/C++、Rust和Go。

2. 安装将代码编译到WebAssembly所需的工具。这可能因所使用的编程语言和特定编译器而异。例如,要将C/C++代码编译到WebAssembly,你可能需要安装Emscripten,这是一个将C/C++编译到WebAssembly的工具链。

3. 用所选的编程语言编写代码,确保遵循WebAssembly输出的任何特定准则。例如,在C/C++中,你可能需要使用特定于Emscripten的特殊函数来与浏览器环境交互。

4. 使用编译器从代码中生成WebAssembly输出。这通常涉及传递命令行选项或设置环境变量,以指定输出应为Wasm格式。

根据性能或大小优化WebAssembly输出(可选)。这可以使用诸如Wasm-opt或Wasm-pack之类的工具来完成。使用JavaScript或其他兼容语言在应用程序或网站中加载生成的WebAssembly代码。

Wasm模块通常使用fetch()API异步加载。

加载模块后,可以使用WebAssembly API对其进行编译和实例化。

要加载并运行WebAssembly模块,首先需要使用JavaScript中的WebAssembly.instantiateStreaming或WebAssembly.intantiate方法创建该模块的实例。这些方法将WebAssembly二进制文件的URL作为参数,并返回一个Promise,该Promise解析为WebAssembly.Module对象和一组导出的函数。

一旦有了WebAssembly.Module对象和导出的函数,就可以调用导出的函数与Wasm模块进行交互。这些函数可以像任何其他JavaScript函数一样被调用,但它们执行的是WebAssembly代码,而不是JavaScript代码。

以下是如何在JavaScript中加载和运行简单WebAssembly模块的示例:

// Load the WebAssembly module from a binary file

fetch('module.wasm')

  .then(response=> response.arrayBuffer())

  .then(bytes=> WebAssembly.instantiate(bytes))

  .then(module=> {

    // Get the exported function from the module

    const add=module.instance.exports.add; 

    // Call the function and print the result

    const result=add(1,2);

    console.log(result);

  });

在本例中,我们使用fetch API将WebAssembly二进制文件加载为ArrayBuffer,然后将其传递给WebAssemble.instantiate方法以创建WebAssemply模块的实例。

然后,我们从实例中获取导出的函数add,用参数1和2调用它,并将结果打印到控制台。

需要注意的是,WebAssembly模块在沙盒环境中运行,不能直接访问JavaScript变量或API。

若要与JavaScript通信,WebAssembly模块必须使用WebAssembly.Memory和WebAssembly.Table对象与在WebAssembly和JavaScript环境之间来回传递的数据和函数指针进行交互。

WebAssembly的性能优势

与其他web技术相比,WebAssembly可以在许多方面提高性能。

首先,可以提前(AOT)或准时(JIT)编译Wasm代码以提高性能。AOT编译允许将WebAssembly代码编译为可以由CPU直接执行的机器代码,而不需要解释器。

另一方面,JIT编译允许WebAssembly代码在运行时实时编译为机器代码,这可以为频繁执行的代码提供更快的启动时间和更好的性能。

此外,WebAssembly可以利用硬件加速,例如SIMD(单指令、多数据)指令,进一步提高性能。SIMD指令允许在单个处理器核心上同时执行多个操作,这可以显著加快数学和其他数据密集型操作的速度。

以下是一些基准测试和示例,说明了使用WebAssembly的性能优势。

——生物计算。该算法很简单,但计算量可能很大。该算法的WebAssembly版本的运行速度大约是JavaScript版本的10倍。

——图像处理。可以使用WebAssembly中提供的SIMD指令对图像处理算法进行高度优化。Wasm版本的图像处理算法的运行速度大约是JavaScript版本的三倍。

——人工智能/机器学习。机器学习算法可以是高度计算密集型的。TensorFlow.js是一个流行的机器学习JavaScript库,但它的性能可以通过使用TensorFlow的WebAssembly版本来提高。在一些基准测试中,Wasm版本的运行速度大约是JavaScript版本的两倍。

——音频处理。WebAssembly可以用来实现实时音频处理算法。Web音频API提供了一种在浏览器中处理音频数据的方法,而音频处理算法的WebAssembly版本的运行速度大约是JavaScript版本的两倍。

Wasm安全注意事项

WebAssembly支持各种安全策略,允许web开发人员控制其代码如何与浏览器资源交互。例如,可以限制Wasm模块访问某些API或执行某些类型的指令。

WebAssembly代码在浏览器的沙盒环境中运行,这限制了它对用户系统的访问。

Wasm代码受同源策略的约束,该策略限制对来自不同来源(即域、协议和端口)的资源的访问。这阻止了Wasm代码访问其不应该访问的网站上的敏感资源或数据。

WebAssembly还通过使用内存安全的执行环境来支持沙盒。这意味着Wasm代码无法访问其自身分配的内存空间之外的内存,从而防止缓冲区溢出攻击和其他与内存相关的漏洞。

WebAssembly还支持陷阱处理程序和权限等功能,陷阱处理程序可以拦截和处理潜在的安全问题,权限允许模块指定需要访问的资源。

此外,Wasm可以使用数字签名进行签名和验证,确保代码在传输或存储过程中未被篡改或修改。WebAssembly代码也可以在安全执行环境中执行,例如在安全飞地内执行,以进一步增强其安全性。

编写安全Wasm代码的最佳实践

在编写WebAssembly代码时,开发人员可以遵循以下几种最佳实践来确保代码的安全性。

——验证输入。与任何代码一样,验证输入以确保它们处于预期的格式和范围是很重要的。这有助于防止诸如缓冲区溢出和整数溢出之类的安全漏洞。

——安全使用内存。WebAssembly提供对内存的低级别访问,这可能是缓冲区溢出和释放后使用漏洞等漏洞的来源。通过检查边界、初始化变量以及在不再需要内存时释放内存来安全地使用内存是很重要的。

——避免对机密数据进行分支。对秘密数据进行分支可能会通过诸如定时攻击之类的副通道泄露信息。为了避免这种情况,最好使用恒定时间算法或确保所有分支占用相同的时间。

——使用类型化数组。WebAssembly提供了可用于以类型安全的方式存储和操作数据的类型化数组。使用类型化数组可以帮助防止缓冲区溢出和类型混淆等漏洞。

——限制对导入函数的访问。如果导入的函数未经正确验证或有意外的副作用,则可能会引入漏洞。为了限制风险,最好限制对导入函数的访问,并验证其输入和输出。

——使用沙盒。为了进一步将WebAssembly代码与应用程序的其他部分隔离开来,它可以在沙盒环境中运行,对文件系统和网络等资源的访问受到限制。这有助于防止攻击者将WebAssembly代码用作攻击的载体。

——保持代码最小化。编写具有明确边界的最小代码,将不可信代码和可信代码区分开来,从而减少攻击面积。

——尽可能避免使用系统调用。相反,使用web API来执行需要输入/输出或其他与系统相关的任务的操作。

——使用加密库。众所周知的加密库,如libsodium、Bcrypt或scrypt,可以帮助保护你的数据安全。

原文链接:

https://thenewstack.io/webassembly/webassembly-what-beginners-need-to-know/

bad3fc3bd1d79a61bff641ab1a494c91.jpeg

798e49d3f4869c5fdfac290affcd249b.jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值