查看原文
其他

WebAssembly:构建本地Web应用程序的新魔法

21CTO 21CTO 2020-11-17

导读:WebAssembly不仅仅是Web中的C/C++。请看本文。

现代Web开发世界是不断创造令人兴奋的区域,每年都会出现新技术,不断改变我们构建Web项目或网页的方式。数十年来,JavaScript一直是Web交互的中坚力量,如今又出现了一个新的挑战者,WebAssembly——简称WASM。


目前人们对JavaScript的生态很满意,但也有一些人群批评JavaScript。近几年,JS开发社区相继推出了像React,Angular以及Vue这样的前端框架,它着实改善了JavaScript的工作流程与功能。


本文就来说探讨WebAssembly是什么,为什么具有突破性前景 ,以及如何使用它。


什么是WebAssembly?




以上半于重塑整个Web开发新潜力的言语听起来是一个很严谨的倡议,或许有的人也会表示怀疑的抬起头。像所有新式技术一样,WebAssembly也会在Web开发人员中引发一些混乱。


为了更明确的定义该术语,我们首先要解决关于WASM不是什么的说明:


1)WebAssembly不是一种编程语言;

2)WebAssembly不仅仅是“Web中的C++”;

3)  WebAssembly本身并不是一种Web技术,因此被称为Web Assembly。


我来尝试定义这个术语:WebAssembly是基于虚拟机的二进制指令集。


它有如下的关键点:


1)它是一台虚拟机,一种处理器,其目的是考虑移植性的情况下将代码编译为实际的体系结构;

2)二进制 指令通过二进制指令集表示;


WebAssembly架构


随着Web开发的发展,对此种技术的需求比例在不断增长:越来越多的开发者需要更多的需求被实现:


1)快速:比JavaScript更快,在某些情况与本地代码一致;

2)安全:不能引入新的漏洞;

3)跨平台:不论是在台式机还是在手机上运行的性能相同;

4)零配置:引入即可正常工作;

5)开发工具就绪:提供完整的支持开发与调试工具。


在此范围中,有很多技术曾经加入这场比赛,但是大多数都失败了,只留下了JavaScript。一些选手包括ActiveX、Flash,还有Google的Native Client和ASM.js。


上面这些技术都还没有达到预期,一起来期待WebAssembly的新特性。


为什么 WebAssembly 如此重要?


编程语言功能虽然强大,但其真正的潜力是其良好的生态。比如JavaScript就是值得说明的例子,它提供了npm之类的强大工具,超越了“只是另一种编程语言”的地位。


有时候,npm也无法提供你想要的答案。假如你正在寻找可以解决问题的库,你只能找到JS之外语言写的库,然后需要将这个库移植到JavaScript上。


而如今,使用WebAssembly可以直接引用外部库,使用几乎相同的功能。


WebAssembly是一种承诺跨平台(包括浏览器)的二进制格式。该技术令人兴奋之处,演变为浏览器即应用程序的新技术。


WebAssembly还提供了垃圾收集支持。它提供对Web API的本地支持与垃圾收集功能,开发者将能够使用其它编程语言来创建Web应用程序:C,C++,Go,Rust,Java,Python,PHP来实现完整的系统。


此外,WebAssembly还提供了可预测、量化的性能,以减少浏览器不同产生差异的能力。


JavaScript与WebAssembly

开发者们通常都心胸开阔,但有时还是会抗拒再重新学习。比如我喜欢的技术比你喜欢的技术好等言论会不断出现。


有一些人甚至把这些技术视为对立的力量,这是一个重要的要点:JavaScript与WASM之间是共生的关系,并非对抗。


WebAssembly可以解决JS的一些缺点。比如asm.js是将一些js“编译”为更小的脚本,但它并不完美,因为解析和编译会花费大量的时间成本。但是WebAssembly在此种情况下的性能却要好得多,它的二进制形式可以最大化启动和执行的速度。


在通常情况下,WebAssembly代码比JS代码更轻,而它却有着相同的功能。另外,WebAssembly模块通常比较重,与JavaScript相比,比较难以分拆。


从性能上来看,JavaScript与WebAssembly有着类似的性能数值。但仅仅是因为性能提升而更换技术是一种短视行为,还要有更多的因素起作用才可行。


有分析数据进一步表明,与JavaScript相比较,WebAssembly提供的性能更加可预测,而JavaScript则会受到浏览器优化的影响。如下图:


WebAssembly与JavaScript基准测试


我们通过canvas来实现图像旋转功能来证明这种奇特现象。让4K图像在不同的浏览器进行测试。


以下是来自 Chrome实验室的数据:


1)浏览器1花费了400毫秒来旋转图像;

2)浏览器2花费了500毫秒;

3)浏览器3花费2.5秒;

4)浏览器4用了8秒。


看到这些数据,很容易得到如下结论:浏览器4是个不良工程的范例。但是我们要意识到,不同的浏览器进行了不同的优化,它也不是早期的Netscape,它是一个功能强大的浏览器。在其它的场景下,也许浏览器1是最慢的浏览器。


而使用WebAssembly重写此代码,则可以在这些浏览器中获得一致的性能。最重要的是,它们的性能变得更可预测,任何开发团队对其变得可控。


我们来看下图,WebAssembly与JavaScript的性能最高峰是相等的。


JavaScript与WebAssembly的速度比较


在不远的将来,JavaScript与WebAssembly的性能等渐渐消失,后者将很快获得对线程以及SIMD(单指令,多维数据的支持),这些将超越JavaScript。


WebAssembly的缺点和警告 

WebAssembly也并非百试不爽的灵丹妙药,它的缺点之一是,需要手动管理内存,这在其它语言属于正常的功能之一。因此,这并不能算做一个缺点,但对于一些JavaScript开发人员而言,当自己可以管理内存时,这意味着整个范式的转变。


另一个警告型缺陷是,WebAssembly代码在浏览器中运行时将被沙箱化,这表示它的功能也仅限JavaScript级别。


虽然如此,然后可以用WebAssembly在浏览器中模仿本地应用程序的功能。


以下是C++功能过渡到WebAssembly和JavaScript的方式:


1)文件系统->Cookie,LocalStorage,IndexedDB

2)  网络->XHR,获取,WebSocket

3)random->Math.random()

4)  异步->轮询+setTimeout()

5)  3D->Canvas,WebGL


还要提到的一点是,并非所有现代浏览器都完全支持WebAssembly。以下是Mozilla开发者从网络截取到2019年8月的数据。



WebAssembly与浏览器兼容性


WebAssembly用例


WebAssembly的目标不是与JavaScript竞争,浪费开发者的资源。相反地,它们解决了Web应用程序的典型瓶颈。


1) Squoosh.app:Web上的桌面级图片压缩



surma在他最近的“面向Web开发人员的WebAssembly”演讲中这样指出,WASM如何帮助团队开发图像压缩程序Squoosh。


从表面上看,Squiosh的功能就是:放入图像->压缩->应用场景使用。这会让一些开发者非常开心,一些图片不再动不动就几十M字节。


const.canvas = document.querySelector("canvas");canvas.toBlob(callback, "image/jpeg", 0.5);


浏览器内部压缩,旨在提高速度而不是提高质量,每个浏览器的功能也不尽相同。比如,在很长时间中,Chrome才开始支持WebP格式。


而基于JavaScript的解决方案质量并不好,该团队转向使用其它语言生态的库,他们找到了一个用C编写的名叫MozJPEG的库,通过WebAssembly对其进行了编译。然后,将浏览器内受限制的编码器替换为通过WebAssembly运行的MozJPEG。




更改和升级浏览器能力是WebAssembly的重要和关键功能之一,此时MozJPEG通过一些专家级编码和压缩选项来增强Squoosh,而这些在浏览器中是无法实现的。


以下是该团队在浏览器中通过JS与Node.js做到的。


使用Emscripten。首先编译该库:


echo "======================="
echo "Compiling mozjpeg..."
echo "======================="
(
cd node_modules/mozjpeg
autorecong -fiv
emconfigure ./configure --without-simd
emmake make libjpeg.la
)


注意的一点是:


configure --without-simd


这表示,线程和simd会极好的帮助开发者,但是 WebAssembly 并不支持这些功能,出于安全原因被禁用。


下面,编写一个JavaScript函数,此函数将返有有在输入中使用的JPEG图像的类型数组。


#include "jpeglib.h"
val encode(
std::string image_in,
int image_width,
int image_height
) {
uint8_t* image_buffer = (uint8_t*) malloc();
// ... Use MozJPEG ...
return val(typed_memory_view(size, image_buffer));
}
EMSCRIPTEN_BINDINGS(mozjpeg_wasm) {
function("encode", &encode);
}


之后,使用称为EMCC的 Emscripten C编译器将全部内容链在一起:


emcc \
--bind \
-I node_modules / mozjpeg \
-o ./mozjpeg_enc.js \
-x Ç + + -std = c ^ + + 11 \
mozjpeg_enc.cpp \
node_modules / mozjpeg / .libs / libjpeg.a


目前,Golang作为支持WA的初级阶段,Google开放平台的surma这样说道:是的!Golang开创性的支持WebAssembly。但是由于Go是一种垃圾收集的语言,为此产生的二进制文件比较大且缓慢,必须编译整个运行时。如果WA具有 本地垃圾收集功能,就会变得更好 。


2)ByteFog:点对点视频共享


byefog是一个P2P式的视频共享的高效且简化的技术。市面上的流媒体服务在高负载下表现都有些差强人意,bytefog通过使用客户端与对等端“共享”视频的一部分,以此节省服务器的资源,从而解决负载问题。在浏览器中,这项技术通过编写浏览器实现。在之后,bytefog决定使用WebAssembly重写。


将浏览器扩展重写成Web版本的特性如下:


1)不需安装。说服潜在用户安装扩展程序是一项不容易的任务,更换为Web版本后则无此问题;

2)统一了代码库;

3)可以同时在多个平台上调试。包括Windows、Linux、MacOS以及Android、iOS和网页。这使发现错误更容易。

4)快速发布与更新。Web应用更方便升级,相比移动端和台式机应用;


小结


我们通过实例让 WebAssembly发挥了魔力。你可能有想法去学习它吗?需要说明的是,不用学习WebAssembly,而是去学一种可以编译为该语言的编程语言,那就是Rust,Rust有着很多的示例,还有更出色的入门资源。


WebAssembly有机会让我们在开发Web应用的模式发生转变。此外在谷歌以及Mozilla等巨头的支持下,其未来会更加光明。


有什么想法,欢迎大家在文底留言。


作者:老夏


别了,JavaScript;你好,WebAssembly

WebAssembly 对比 JavaScript 及其使用场景

WebAssembly 浏览器技术指南


21CTO学院PHP全栈工程师隆重开营啦,报名获得一线互联网公司就业机会!


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存