找回密码
 会员注册
查看: 19|回复: 0

初识WebAssembly

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64756
发表于 2024-10-10 11:08:44 | 显示全部楼层 |阅读模式
初识WebAssembly 初识WebAssembly 陈奇奇 贝壳产品技术 贝壳产品技术 “贝壳产品技术公众号”作为贝壳官方产品技术号,致力打造贝壳产品、技术干货分享平台,面向互联网/O2O开发/产品从业者,每周推送优质产品技术文章、技术沙龙活动及招聘信息等。欢迎大家关注我们。 242篇内容 2021年09月08日 19:32 2019年12月5日,继HTML、CSS 和 JavaScript 之后,WebAssembly加入了Web 标准大家庭,随着其不断完善,作为一门新兴起的技术,在 JavaScript 圈非常的火!人们都在谈论它多么多么快,会怎样怎样改变Web 开发领域。W3C 项目负责人 Philippe LeHégaret 评价为:“WebAssembly 的到来扩展了仅仅用开放的 Web 平台技术就可以实现的应用程序的范围。在当今机器学习和人工智能越来越普遍的世界中,重要的是在不损害用户安全性的情况下在 Web 上运行高性能程序。”那么究竟什么是WebAssembly,为什么会诞生WebAssembly,它凭什么实现了高性能,为什么那么快,又会不会取代JS呢?接下来这篇文章对其做一个简单的介绍。什么是WebAssembly首先,我们要知道WebAssembly到底是什么;MDN的官方解释是:是为高效执行和紧凑表示而设计的运行在现代处理器(包括浏览器)中的一种快速、安全、可移植的底层代码格式,具有紧凑的二进制格式,可以以接近本机的性能运行;我们可以总结为:WebAssembly不是一种语言,而是一种新的编码方式,它是继html、css、JavaScript之后又一种可以在浏览器中运行的文件格式。是一种可以使用非 JavaScript 编程语言编写代码的技术方案。具有紧凑的二进制格式,可以接近原生的性能运行诞生背景1995 年 JavaScript 诞生,其设计初衷并不是为了执行起来快,是为了解决一些简单的网页互动(比如,检查“用户名”是否填写),并没有考虑复杂应用的需要。2008 年,由于其前十年发展迅速,浏览器厂商竞争 => 浏览器性能大战引入了即时编译器,又称 JIT;基于 JIT 的模式,JavaScript 代码的运行渐渐变快,性能提升。接着,性能的提升使得 JavaScript 的应用范围得到很大的扩展,催生了Node.js,Electron 等技术,但是,JS的根本问题逐渐暴露出来:语法太灵活导致开发大型 Web 项目困难;性能不能满足一些场景的需要。各大浏览器厂商纷纷提出了自己的解决方案,比如:微软的 TypeScript 通过为 JS 加入静态类型检查来改进 JS 松散的语法,提升代码健壮性;谷歌的 Dart 则是为浏览器引入新的虚拟机去直接运行 Dart 程序以提升性能;火狐的asm.js则是取 JS 的子集,JS 引擎针对 asm.js 做性能优化但是,这些方案各有各的缺点,且互不兼容,这违背了 Web 的宗旨。这就需要一个统一的技术规范方案。所以,WebAssembly诞生了。在 2015 年,WebAssembly首次发布,并提供了一个运行在 Unity 下的游戏的小型演示。这款游戏是直接在浏览器中运行的。2019年12月5日,万维网联盟(W3C)宣布,WebAssembly 核心规范是一种正式的 Web 标准。由此,WebAssembly正式活跃在web领域,继JIT的模式的提出之后,WebAssembly很有可能是浏览器运行代码机制的另一大转折点。为什么 WebAssembly 更快?WebAssembly的高性能是相对js而言的,那么在我们 JavaScript 和 WebAssembly 之间的性能差前,我们首先需要理解 JS 引擎所做的工作。目前的浏览器,其在编程中,将代码翻译成机器语言的方式,比较常见的方法是 JIT 编译器;下面我们就以JIT 编译器为例,大概的给出一个程序的启动步骤和性能:图中的每一个颜色条都代表了不同的任务:文件抓取:从服务器获取文件所花费的时间解析:把源代码变成解释器可以运行的代码所花的时间;编译和优化:表示基线编译器和优化编译器花的时间。重优化阶段:当 JIT 发现优化假设错误,丢弃优化代码所花的时间。包括重优化的时间、抛弃并返回到基线编译器的时间。执行阶段:执行代码的时间。垃圾回收阶段:垃圾回收,清理内存的时间。下面我们来对比下WebAssembly和JS在各个阶段,所花费的时间,由此比较两者性能:文件抓取阶段因为WebAssembly可以以二进制形式,所以与JS等效的WebAssembly文件更小;这就表示WebAssembly 比 JavaScript 抓取文件更快。即使 JavaScript 进行了压缩,WebAssembly 文件的体积也比 JavaScript 更小。这一段耗时的对比,在网速慢的情况对比会更加鲜明。解析阶段当到达浏览器时,JavaScript 源代码会解析成抽象语法树(AST)。解析的目的是将AST转化成中间代码(叫做字节码),提供给 JS 引擎编译;然而,WebAssembly 不需要被转换,因为它已经是字节码了。它仅仅需要被解码并确定没有任何错误。编译和优化阶段JS是弱类型编程语言,初始化变量时无须显式地指出变量地具体类型,整个变量地类型完全由代码编译器在代码地运行过程中进行推断。C语言等强类型语言可以提前将程序等源代码进行静态编译和优化,最后直接生成相应的经过优化的二进制机器码供CPU执行。转化成的WebAssembly 与机器代码更接近。也就是说,相对于JS而言,WebAssembly在此阶段会更快,因为:编译器不需要在运行代码时花费时间去观察代码中的数据类型,在开始编译时做优化编译器不需要对同样的代码做不同版本的编译。很多优化已经在 LLVM 前完成,所以编译和优化的工作很少。重新优化有些情况下,JIT 会反复地进行“抛弃优化代码重优化”过程。比如:JIT在优化假设阶段,所做的假设在执行阶段,发现假设是不正确的时候;当循环中发现本次循环所使用的变量类型和上次循环的类型不一样,或者原型链中插入了新的函数,都会使 JIT 抛弃已优化的代码。而反优化过程有两部分开销:1. 需要花时间丢掉已优化的代码并且回到基线版本。2. 如果函数依旧频繁被调用,JIT 可能会再次把它发送到优化编译器,又做一次优化编译,这是在做无用功。相比而言,在 WebAssembly 中,类型都是确定了的,所以 JIT 不需要根据变量的类型做优化假设。也就是说 WebAssembly 没有重优化阶段。执行严格来说,我们自己就可以写出执行效率很好的JS代码。但是,前提是我们需要了解JIT的优化机制和内部实现;例如你要知道什么样的代码编译器会对其进行特殊处理,然而大多数的开发者做不到这点的。另一方面,即使开发者知道 JIT 的内部机制,也很难写出符合 JIT 标准的代码,因为人们通常为了代码可读性更好而使用的编码模式,恰恰不合适编译器对代码的优化。再加上,JIT 会针对不同的浏览器做不同的优化,所以对于一个浏览器优化的比较好,很可能在另外一个浏览器上执行效率就比较差。正是因为这样,执行 WebAssembly 通常会比较快:很多 JIT 为 JavaScript 所做的优化在 WebAssembly 并不需要。WebAssembly 就是为了编译器而设计的,开发人员不直接对其进行编程,这样就使得 WebAssembly 专注于提供更加理想的指令;执行效率方面,不同的代码功能有不同的效果,一般来讲执行效率会提高 10% - 800%。垃圾回收JavaScript 中,开发者不需要手动清理内存中不用的变量。JS 引擎会自动地做这件事情,这个过程叫做垃圾回收。可是,当你想要实现性能可控,垃圾回收可能就是个问题了。垃圾回收器会自动开始,这是不受你控制的,所以很有可能它会在一个不合适的时机启动。目前的大多数浏览器已经能给垃圾回收安排一个合理的启动时间,不过这还是会增加代码执行的开销。目前为止,WebAssembly 不支持垃圾回收。内存操作都是手动控制的(像 C、C++一样)。这对于开发者来讲确实增加了些开发成本,不过这也使代码的执行效率更高。总结使用WebAssembly,可以更快地在 web 应用上运行代码。这里有几个WebAssembly代码运行速度比JavaScript 高效的原因:文件加载:WebAssembly文件体积更小,所以下载速度更快;解析:解码WebAssembly比解析JavaScript 要快;编译和优化:编译和优化所需的时间较少,因为在将文件推送到服务器之前已经进行了更多优化,JavaScript 需要为动态类型多次编译代码;重新优化:WebAssembly 代码不需要重新优化,因为编译器有足够的信息可以在第一次运行时获得正确的代码;执行:执行可以更快,WebAssembly 指令更接近机器码;垃圾回收:目前WebAssembly 不直接支持垃圾回收,垃圾回收都是手动控制的,所以比自动垃圾回收效率更高。WebAssembly是否会取代JavaScript?上面比较了WebAssembly和JS的性能,发现在大多数情况下,同一个任务 WebAssembly 比 JavaScript 表现更好,那么问题来了,WebAssembly会不会取代JS呢?个人认为,WebAssembly的出现是不会取代JS的,它的设计初衷是为了和JS一起协同合作的,原因如下:JS是动态类型的,它灵活且富有表达性,不需要编译环节以及拥有一个巨大的能够提供强大框架、库和其他工具的生态系统;WebAssembly提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在Web中运行;WebAssembly 不具备 DOM 操作能力;JavaScript 和 WebAssembly 之间是可以互相调用。正如MDN官网上所说:“我们可以在同一个应用中利用WebAssembly的性能和威力以及JavaScript的表达力和灵活性”。WebAssembly 应用小实例1. 模块生成我们可以通过安装诸如Emscripten的工具把高级语言编译为.wasm文件 步骤:gitclonehttps://github.com/juj/emsdk.gitcdemsdk#在Linux或者MacOSX上./emsdkinstall--build=Releasesdk-incoming-64bitbinaryen-master-64bit./emsdkactivate--global--build=Releasesdk-incoming-64bitbinaryen-master-64bit#如果在你的macos上获得以下错误Error:NotoolorSDKfoundbyname'sdk-incoming-64bit'#请执行./emsdkinstalllatest#按照提示配置环境变量即可./emsdkactivatelatest进入emsdk文件夹,输入以下命令来让你进入接下来的流程,编译一个样例C程序到asm.js或者wasm。source./emsdk_env.shEmscripten功能比较强大,我们可以直接生成HTML和JS模版,也可以生成专门的wasm文件 比如:将math.c 生成 math.wasmemccmath.c-Os-sWASM=1-sSIDE_MODULE=1-omath.wasm此时仅生成 math.wasm而emcchello.c-sWASM=1-ohello.html此命令则会生成:1). hello.wasm:二进制的wasm模块代码2). hello.js:一个包含了用来在原生C函数和JavaScript/wasm之间转换的胶水代码的JavaScript文件3). hello.html:一个用来加载,编译,实例化你的wasm代码并且将它输出在浏览器显示上的一个HTML文件2. 模块加载wasm模块创建完成之后,我们可以获取wasm资源,然后对模块进行实例化来完成模块的加载3. 获取 wasm 资源获取资源的方式和我们常规的获取方式一致,通过 XMLHttpRequest 或 Fetch,此处以 Fetch 为例,该函数返回一个可以解析为 Response 对象的 promise。接着使用 arrayBuffer 函数把响应转换为带类型数组,该函数返回一个可以解析为带类型数组的 promise。4. 模块实例化我们获取的是 wasm 模块,最后使用 WebAssembly.instantiate 函数进行实例化。#javascript调用WebAssembly的方法math.cintadd(intx,inty){returnx+y;}intsquare(intx){returnx*x;}效果:我们可以看到 math.c中的add和square方法被js成功引用。参考文章WebAssembly 基本介绍https://juejin.cn/post/6970606101943451684#heading-1MDNhttps://developer.mozilla.org/zh-CN/docs/WebAssembly编译 C/C++ 为 WebAssemblyhttps://developer.mozilla.org/zh-CN/docs/WebAssembly/C_to_wasm上手WebAssemblyhttps://juejin.cn/post/6844904190905417741#heading-2几张图让你看懂WebAssemblyhttps://www.jianshu.com/p/bff8aa23fe4d前端要懂的WebAssembly 前世今生https://juejin.cn/post/6844904192541196295#heading-40 预览时标签不可点 FE33大前端69FE · 目录#FE上一篇【GMTC·贝壳】VR及3D技术在Web端架构设计与实践下一篇从babel plugin插件入门到babel plugin import 源码解析关闭更多小程序广告搜索「undefined」网络结果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-28 21:31 , Processed in 0.485498 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表