avaScript与WebAssembly进行比较+在哪些情况下会优于JavaScript

更新日期: 2018-06-27阅读量: 2103标签: js知识

这是专门探索JavaScript及其构建组件的系列。在识别和描述核心元素的过程中,我们还分享了构建SessionStack时使用的一些经验法则,这是一个轻量级但健壮且高性能的JavaScript应用程序,以帮助用户实时查看和重现其Web应用程序的缺陷。

如果你错过了前面的章节,你可以在这里找到它们:

这次我们来分析WebAssembly的工作原理,以及在如下几个方面和JavaScript进行比较:加载时间,执行速度,垃圾回收,内存使用情况,平台API访问,调试,多线程和可移植性。

首先,让我们看看WebAssembly的功能。

WebAssembly(又名wasm)是一种高效的,低级别的编程语言。 它让我们能够使用JavaScript以外的语言(例如C,C ++,Rust或其他)编写程序,然后将其编译成WebAssembly,进而生成一个加载和执行速度非常快的Web应用程序。

加载时间

为了加载JavaScript,浏览器必须加载所有.js文本文件。 WebAssembly在浏览器中加载速度更快,因为只有已编译的wasm文件才通过互联网传输。并且wasm是一种非常简洁的二进制格式的低级汇编语言,文件更小。

执行

目前Wasm 比本地代码执行速度慢20%。这倒是一个令人吃惊的结果,不过,这是一种编译到沙盒环境中的格式并且在很多约束条件下运行,以确保它没有安全漏洞或者很难攻防这个漏洞。与真实的本地代码相比,其实速度下降很小。但是,未来它会更快。

更好的是,它与浏览器无关 - 所有主要引擎都增加了对WebAssembly的支持,并且现在提供类似的执行时间。 为了理解WebAssembly与JavaScript相比执行得有多快,您应该先阅读我们关于 JavaScript引擎如何工作 )的文章。 我们来看看简单看看V8中发生了什么:


V8 Approach: lazy compilation

在左边,我们有一些JavaScript源代码,包含JavaScript函数。它首先需要进行分析,以便将所有字符串转换为标记并生成抽象语法树(AST)。AST是JavaScript程序逻辑的内存表示。一旦生成这种表示,V8直接转到机器码。一般来说,只需要遍历树,生成机器代码,便生成了编译好的函数。从这个过程可以看出,这个阶段并没有编译速度的优势。 现在,我们来看看V8管道在下一阶段的功能:


V8管道设计

这次我们有TurboFan,V8的优化编译器之一。当您的JavaScript应用程序正在运行时,很多代码在V8中运行。TurboFan可以监控运行缓慢的内容,是否存在瓶颈和热点以优化它们。它将它们推送到后端,这是一个优化的JIT,它可以优化那些非常耗cpu的代码。 虽然它解决了上述问题,但是新的问题在于:分析代码并决定优化哪些内容的过程也会消耗CPU。这反过来又意味着更高的电池消耗,特别是在移动设备上。 然而,wasm不一样在于,它会被插入工作流程中,如下所示:


V8管道设计+ WASM

在汇编阶段,wasm已经优化过了。最重要的是,解析也不是必需的。你有一个优化的二进制文件,可以直接hook到可以生成机器码的后端。所有优化都由编译器在前端完成。 这使得执行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,则您有一组Web APIs,Web应用程序可以调用它来控制Web浏览器/设备功能并访问DOMCSSOMWebGLIndexedDBWeb Audio API等。

然而,WebAssembly模块无法访问任何平台API。一切都是由JavaScript调用的。如果您想访问WebAssembly模块中的某些平台特定的API,则必须通过JavaScript调用它。

例如,如果你想console.log,你必须通过JavaScript来调用它,而不是你的C ++代码。这些JavaScript调用的成本有所降低。

这并不总是如此。该规范将在未来为平台API提供wasm,并且您将能够在没有JavaScript的情况下发布您的应用程序。

Source maps

当您精简JavaScript源代码时,您需要一种正确方式调试它。这就需要Source Maps。基本上, Source Maps 是一种将组合/缩小文件映射回未建立状态的方法。当您为生产而构建时,同时缩小和组合您的JavaScript文件,您将生成一个包含原始文件信息的源映射。当您在生成的JavaScript中查询某一行和列号时,可以在返回原始位置的源地图中执行查找。

WebAssembly目前不支持source maps,因为没有规范,但最终会支持(可能很快)。 当您在C ++代码中设置断点时,您将看到C ++代码而不是WebAssembly。

多线程

JavaScript在单个线程上运行。有很多方法可以利用Event Loop并利用异步编程,如我们关于该主题的文章中详细描述的那样

JavaScript也使用Web Workers,但他们有一个非常具体的用例 - 基本上,可能阻塞主UI线程的任何CPU密集计算都可以进入到Web Worker中来提高性能。但是,Web Workers无法访问DOM。

WebAssembly目前不支持多线程。但是,这可能是未来的事情。Wasm将更接近本地线程(例如C ++样式线程)。拥有“真实”的线程将在浏览器中创造出许多新的机会。当然,这将打开更多滥用可能性的大门。 可移植性

可移植性

如今,JavaScript几乎可以在任何地方运行,从浏览器到服务器端甚至嵌入式系统。

WebAssembly被设计为安全和便携。就像JavaScript一样。它将运行在支持主机的每个环境中(例如每个浏览器)。就像当年的Java的Applets,WebAssembly有相同的可移植性的愿景。

在JavaScript上使用WebAssembly,哪些场景更合适?

在WebAssembly的第一个版本中,主要关注CPU占用大的计算(例如处理数学)。想到的最主流的用途是游戏 - 那里有大量的像素操作。您可以使用您习惯的OpenGL在C ++ / Rust中编写您的应用程序,并将其编译为wasm。它会在浏览器中运行。 看看这个(在Firefox中运行) -  http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html。这是 Unreal engine.。

另一种使用WebAssembly(性能方面)可能有意义的情况是实现一些库,这是一个CPU密集型工作。例如,一些图像处理。

如前所述,由于大多数处理步骤都是在编译期间提前完成的,因此wasm可以减少移动设备上的电池消耗(取决于引擎)。

将来,即使您实际上没有编写编译代码,您也可以使用WASM二进制文件。您可以在npm中找到开始使用此方法的项目。

对于DOM操作和沉重的平台API使用,使用JavaScript确实很有意义,因为它不会增加额外的开销,并且具有本地提供的API。

SessionStack中,我们不断增强JavaScript的性能,以编写高度优化且高效的代码。我们的解决方案需要提供超快的性能,因为我们不能阻碍客户应用的性能。将SessionStack集成到生产Web应用程序或网站后,它会开始记录所有内容:所有DOM更改,用户交互,JavaScript异常,堆栈跟踪,失败的网络请求和调试数据。所有这些都在您的生产环境中进行,而不会影响产品的任何UX和性能。我们需要大量优化我们的代码并尽可能使其异步。

不仅仅是库文件,当在SessionStack中重放用户回话时,我们会渲染用户浏览器中发生的所有事件,并且我们必须重构整个状态,允许您在会话时间线中来回跳转。因为没有更好的选择,为了做到这一点,我们大量使用了JavaScript提供的异步机会。

借助WebAssembly,我们将能够将一些最繁重的处理和渲染转换为更适合作业的语言,并将数据收集和DOM操作保留为JavaScript。

如果你想尝试下SessionStack,你可以免费开始。有一个免费的计划),每月提供1000个会话。


参考:

翻译来源:https://www.zcfy.cc/


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: https://www.fly63.com/article/detial/897

JavaScript中“javascript:void(0) ”是什么意思

expression 是一个要计算的 Javascript 标准的表达式。表达式外侧的圆括号是可选的,鉴于规范化,以及养成好习惯,建议写上去。当我们使用 void 操作符指定超级链接时,表达式会被计算但是不会在当前文档处装入任何内容。

js原型链,Javascript重温OOP之原型与原型链

js的原型链,得出了一个看似很简单的结论。对于一个对象上属性的查找是递归的。查找属性会从自身属性(OwnProperty)找起,如果不存在,就查看prototype中的存在不存在。

javascript中的依赖注入

使用没有依赖的模块,显然这是很难实现的。即使你创建了很好的像黑盒一样的组件,但总有个将所有部分合并起来的地方。这就是依赖注入起作用的地方,当前来看,高效管理依赖的能力是迫切需要的,本文总结了原作者对这个问题的看法。

一眼看穿JS变量,作用域和内存问题

这篇文章将梳理下环境,作用域链,变量对象和活动对象,以及内存管理问题。基本类型和引用类型的值,我们都知道JS中的数据类型有两大类,基本数据类型和引用数据类型,下面从三个方面来解剖他们

js dom是什么?_JS中的DOM知识概览

JS中的DOM知识概览:文档对象模型,是针对 HTML 和 XML 文档的一个 API (应用程序编程接口), 描绘了一个层次化的节点树。 web 浏览器浏览一个页面的时候,DOM 就在幕后把你编辑的网页文档转换成一个文档对象。

为什么JavaScript开发如此疯狂

Web开发中其他一切对你而言都是小菜一碟,但当你深入探究JavaScript的时候,不免有一种“众人皆醒你独醉”的悲壮——好像其他人都知道你不知道的一些大的基础的知识内容,并且这些内容可以帮助你理解所有知识

TS与JS中的Getters和Setter究竟有什么用?

在本文中,我们讨论了getter 和 setter 在现代 Web 开发中的实用性。它们有用吗?什么时候使用它们是有意义的?尽管我不同意 getter 和 setter 完全是一个反模式。但它们在几种情况下能带来更多的实用性。

你不知道的 js 保留字

先是笼统的说一下有什么保留字,保留字的话根据犀牛书的划分,可有分为以下几类:基础保留字、严格模式下的保留字、严格模式下的不完全保留字、ECMAScript3的保留字、ECMAScipt 5 的保留字、全局变量和函数

base91 for javascript

原理和 base64 是一样的,ASCII 共有94个可打印字符,base64 使用了其中 64 个,base91 使用了 91 个。

原生js获取当前周数

通过原生Js根据日期获取对应日期的周数,例如今天是2018-01-01那么获取该日期在这一年的周数就为1,有需要的朋友可以参考下。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!