当前位置: 首页 > Web前端 > HTML

JavaScript与WebAssembly比较

时间:2023-04-02 18:35:25 HTML

本文由云+社区发布作者:QQ音乐前端团队在识别和描述核心元素的过程中,我们分享了在构建SessionStack时使用的一些经验法则,SessionStack是一个轻量级但健壮的以及高性能JavaScript应用程序,可帮助用户实时查看和重现其Web应用程序中的缺陷。这次我们分析WebAssembly的工作原理,并将其与JavaScript在以下方面进行比较:加载时间、执行速度、垃圾收集、内存使用、平台API访问、调试、多线程和可移植性。WebAssembly的特性WebAssembly(又名wasm)是一种高效的低级编程语言。它允许我们用JavaScript以外的语言(例如C、C++、Rust或其他语言)编写程序,然后将这些程序编译成WebAssembly,从而生成加载和执行速度非常快的Web应用程序。加载时间为了加载JavaScript,浏览器必须加载所有.js文本文件。WebAssembly在浏览器中加载速度更快,因为只有编译后的wasm文件通过互联网传输。wasm是一种低级汇编语言,采用非常简洁的二进制格式,文件较小。执行Wasm目前比本机代码执行慢20%。这是一个令人惊讶的结果,但是,这是一种编译到沙盒环境中并在许多约束下运行以确保它没有安全漏洞或很难被利用的格式。与真正的本机代码相比,速度下降实际上非常小。但是,将来它会更快。更好的是,它与浏览器无关——所有主要引擎都增加了对WebAssembly的支持,并且现在提供相似的执行时间。让我们快速看一下V8中发生了什么:V8方法:惰性编译在左侧,我们有一些JavaScript源代码,其中包含JavaScript函数。首先需要对其进行分析,以便将所有字符串转换为标记并生成抽象语法树(AST)。AST是JavaScript程序逻辑的内存表示。一旦生成了这种表示,V8就直接进入机器代码。一般来说,只需要遍历树生成机器码,然后生成编译函数即可。从这个过程可以看出,这个阶段并不具备编译速度的优势。现在,让我们看看V8流水线在下一阶段的作用:V8流水线设计这次我们有TurboFan,它是V8的优化编译器之一。当你的JavaScript应用程序运行时,很多代码都在V8中运行。TurboFan监控运行缓慢的程序,找出瓶颈和热点以优化它们。它将它们推送到后端,这是一个优化的JIT,它优化了那些非常占用cpu的代码。在解决上述问题的同时,又出现了一个新问题:分析代码并决定优化什么的过程也会消耗CPU。这反过来意味着更高的电池消耗,尤其是在移动设备上。然而,wasm的不同之处在于它被插入到工作流中,如下所示:内存模型WebAssembly可信和不可信状态例如,编译成WebAssembly的C++程序的内存是一个连续的内存块,其中没有“漏洞”。有助于提高安全性的wasm特性之一是执行堆栈与线性内存分离的概念。在C++程序中,你有一个内存堆,你从堆的底部分配,并从顶部增长堆。这会产生一个被许多恶意软件利用的漏洞:使用单个指针,您可以通过在您不应访问的堆栈内存中查找数据来更改变量。WebAssembly遵循完全不同的模型。执行栈与WebAssembly程序本身是分开的,所以你不能在那里修改它,也不能改变变量之类的东西。此外,这些函数使用整数偏移量而不是指针。函数指向一个间接函数表。这些直接计算的数字然后跳转到模块内的函数中。它的构建方式使您可以同时加载多个wasm模块,形成多个索引列表,并且一切正常。有关JavaScript中的内存模型和管理的更多信息,您可以查看这篇关于该主题的非常详细的帖子。垃圾收集您已经知道JavaScript的内存管理是使用垃圾收集器处理的。WebAssembly的情况有点不同。它支持手动管理内存的语言。你可以在WASM上自定义垃圾回收模块,但是这样比较复杂。目前,WebAssembly是围绕C++和RUST用例设计的。由于wasm非常低级,因此仅比汇编语言高一级的编程语言很容易编译。C可以使用普通的malloc,C++可以使用智能指针,Rust使用完全不同的模式(完全不同的主题)。这些语言不使用GC,因此它们不需要所有复杂的运行时东西来跟踪内存。WebAssembly很适合他们。另外,这些语言并非100%设计用于调用复杂的JavaScript事物,例如DOM。用C++编写整个HTML应用程序没有意义,因为C++不是为它设计的。在大多数情况下,当工程师编写C++或Rust时,他们的目标是WebGL或高度优化的库(例如繁重的数学计算)。然而,未来WebAssembly将支持不附带GC的语言。平台API访问取决于执行JavaScript的运行时,并且可以通过您的JavaScript应用程序访问特定于平台的API。例如,如果您在浏览器中运行JavaScript,您将拥有一组WebAPI,Web应用程序可以调用这些API来控制Web浏览器/设备功能并访问DOM、CSSOM、WebGL、IndexedDB、WebAudioAPI等。但是,WebAssembly模块无权访问任何平台API。一切都由JavaScript调用。如果你想在WebAssembly模块中访问一些特定于平台的API,你必须通过JavaScript调用它。例如,如果你想要console.log,你必须从JavaScript调用它,而不是你的C++代码。这些JavaScript调用的成本已经降低。这并非总是如此。该规范将在未来为平台API提供wasm,您将能够在没有JavaScript的情况下发布您的应用程序。Sourcemaps当你缩小JavaScript源代码时,你需要一个正确的方法来调试它。这需要SourceMaps。基本上,SourceMaps是一种将组合/缩小文件映射回未构建状态的方法。当您为生产而构建时,在缩小和组合JavaScript文件的同时,您将生成一个源映射,其中包含有关原始文件的信息。当您在生成的JavaScript中查询特定行号和列号时,您可以在返回原始位置的源映射中执行查找。WebAssembly目前不支持源地图,因为没有规范,但最终(可能很快)。当您在C++代码中设置断点时,您将看到C++代码而不是WebAssembly。多线程JavaScript在单个线程上运行。有很多方法可以利用事件循环和异步编程。JavaScript也使用WebWorker,但它们有一个非常具体的用例——基本上,任何可能阻塞主UI线程的CPU密集型计算都可以进入WebWorker以提高性能。但是,WebWorker无法访问DOM。WebAssembly目前不支持多线程。然而,这可能是未来的事情。Wasm将更接近原生线程(例如C++风格的线程)。拥有“真正的”线程将在浏览器中创造许多新的机会。当然,这为更多的滥用可能性打开了大门。可移植性如今,JavaScript几乎可以在任何地方运行,从浏览器到服务器端甚至嵌入式系统。WebAssembly被设计成安全和便携的。就像JavaScript一样。它将在支持主机的每个环境(例如每个浏览器)中运行。就像当时的JavaApplets一样,WebAssembly也有同样的可移植性愿景。哪些场景更适合使用WA在WebAssembly的第一个版本中,主要关注于CPU密集型计算(例如处理数学)。想到的最主流的用途是游戏——那里有很多像素操作。您可以使用您习惯的OpenGL在C++/Rust中编写您的应用程序,并将其编译为wasm。它将在浏览器中运行。看看这个(在Firefox中运行)http://s3.amazonaws.com/mozil…。这是Unreal引擎。另一种使用WebAssembly(性能方面)可能有意义的情况是实现一些库,这是一项CPU密集型工作。比如一些图像处理。如前所述,wasm可以减少移动设备的电池消耗(取决于引擎),因为大多数处理步骤都是在编译期间提前完成的。将来,即使您实际上不编写编译代码,也可以使用WASM二进制文件。你可以在NPM中找到开始使用此方法的项目。对于DOM操作和繁重的平台API使用,使用JavaScript确实很有意义,因为它不会增加额外的开销并且原生提供了API。在SessionStack中,我们不断增强JavaScript的性能以编写高度优化和高效的代码。我们的解决方案需要提供超快的性能,因为我们不能阻碍客户应用程序的性能。在将SessionStack集成到生产Web应用程序或网站后,它会开始记录所有内容:所有DOM更改、用户交互、JavaScript异常、堆栈跟踪、失败的网络请求和调试数据。所有这一切都发生在您的生产环境中,而不会影响您产品的任何用户体验和性能。我们需要大量优化我们的代码并使其尽可能异步。不仅仅是库,当在SessionStack中重播用户会话时,我们会呈现用户浏览器中发生的所有事件,并且我们必须重构整个状态以允许您在会话时间轴中来回跳转。为了做到这一点,由于缺乏更好的选择,我们大量使用JavaScript提供的异步机会。使用WebAssembly,我们将能够将一些最繁重的处理和渲染工作卸载到更适合该工作的语言中,并将数据收集和DOM操作保持为JavaScript。如果您想尝试一下SessionStack,您可以免费开始使用。有一个免费计划)每月提供1000次会话。参考:https://www.youtube.com/watch...https://www.youtube.com/watch...本文已被腾讯云+社区发布在各个渠道获取更多新鲜技术干货,你可以关注我们腾讯云技术社区-云家社区公众号和知乎代理号