WebAssembly完全入门——了解wasm的前世今身

news2024/12/27 10:46:06

前言

        接触WebAssembly之后,在google上看了很多资料。感觉对WebAssembly的使用、介绍、意义都说的比较模糊和笼统。感觉看了之后收获没有达到预期,要么是文章中的例子自己去实操不能成功,要么就是不知所云、一脸蒙蔽。本着业务催生技术的态度,这边文章就诞生了。前部分主要是对WebAssembly的背景做一些介绍,WebAssembly是怎么出现的,优势在哪儿。如果想直接开始撸代码试试效果,可以直接跳到最后一个板块。

WebAssembly是什么?

定义

首先我们给它下个定义。

WebAssembly 或者 wasm 是一个可移植、体积小、加载快并且兼容 Web 的全新格式

例子

当然,我知道,即使你看了定义也不知道WebAssembly到底是什么东西。废话不多说,我们通过一个简单的例子来看看WebAssembly到底是什么。

上图的左侧是用C++实现的求递归的函数。中间是十六进制的Binary Code。右侧是指令文本。可能有人就问,这跟WebAssembly有个屁的关系?其实,中间的十六进制的Binary Code就是WebAssembly。

编译目标

大家可以看到,其可写性和可读性差到无法想象。那是因为WebAssembly不是用来给各位用手一行一行撸的代码,WebAssembly是一个编译目标。什么是编译目标?当我们写TypeScript的时候,Webpack最后打包生成的JavaScript文件就是编译目标。可能大家已经猜到了,上图的Binary就是左侧的C++代码经过编译器编译之后的结果。

WebAssembly的由来

性能瓶颈

在业务需求越来越复杂的现在,前端的开发逻辑越来越复杂,相应的代码量随之变的越来越多。相应的,整个项目的起步的时间越来越长。在性能不好的电脑上,启动一个前端的项目甚至要花上十多秒。这些其实还好,说明前端越来越受到重视,越来越多的人开始进行前端的开发。

但是除了逻辑复杂、代码量大,还有另一个原因是JavaScript这门语言本身的缺陷,JavaScript没有静态变量类型。这门解释型编程语言的作者Brendan Eich,仓促的创造了这门如果被广泛使用的语言,以至于JavaScript的发展史甚至在某种层面上变成了填坑史。为什么说没有静态类型会降低效率。这会涉及到一些JavaScript引擎的一些知识。

静态变量类型所带来的问题

这是Microsoft Edge浏览器的JavaScript引擎ChakraCore的结构。我们来看一看我们的JavaScript代码在引擎中会经历什么。

  • JavaScript文件会被下载下来。
  • 然后进入Parser,Parser会把代码转化成AST(抽象语法树).
  • 然后根据抽象语法树,Bytecode Compiler字节码编译器会生成引擎能够直接阅读、执行的字节码。
  • 字节码进入翻译器,将字节码一行一行的翻译成效率十分高的Machine Code.

在项目运行的过程中,引擎会对执行次数较多的function记性优化,引擎将其代码编译成Machine Code后打包送到顶部的Just-In-Time(JIT) Compiler,下次再执行这个function,就会直接执行编译好的Machine Code。但是由于JavaScript的动态变量,上一秒可能是Array,下一秒就变成了Object。那么上一次引擎所做的优化,就失去了作用,此时又要再一次进行优化。

asm.js出现

所以为了解决这个问题,WebAssembly的前身,asm.js诞生了。asm.js是一个Javascript的严格子集,合理合法的asm.js代码一定是合理合法的JavaScript代码,但是反之就不成立。同WebAssembly一样,asm.js不是用来给各位用手一行一行撸的代码,asm.js是一个编译目标。它的可读性、可读性虽然比WebAssembly好,但是对于开发者来说,仍然是无法接受的。

asm.js强制静态类型,举个例子。

function asmJs() {
    'use asm';
    
    let myInt = 0 | 0;
    let myDouble = +1.1;
}

为什么asm.js会有静态类型呢?因为像0 | 0这样的,代表这是一个Int的数据,而+1.1则代表这是一个Double的数据。

asm.js不能解决所有的问题

可能有人有疑问,这问题不是解决了吗?那为什么会有WebAssembly?WebAssembly又解决了什么问题?大家可以再看一下上面的ChakraCore的引擎结构。无论asm.js对静态类型的问题做的再好,它始终逃不过要经过Parser,要经过ByteCode Compiler,而这两步是JavaScript代码在引擎执行过程当中消耗时间最多的两步。而WebAssembly不用经过这两步。这就是WebAssembly比asm.js更快的原因。

WebAssembly横空出世

所以在2015年,我们迎来了WebAssembly。WebAssembly是经过编译器编译之后的代码,体积小、起步快。在语法上完全脱离JavaScript,同时具有沙盒化的执行环境。WebAssembly同样的强制静态类型,是C/C++/Rust的编译目标。

WebAssembly的优势

WebAssembly和asm.js性能对比

下面的图是Unity WebGL使用和不使用WebAssembly的起步时间对比的一个BenchMark,给大家当作一个参考。
可以看到,在FireFox中,WebAssembly和asm.js的性能差异达到了2倍,在Chrome中达到了3倍,在Edge中甚至达到了6倍。通过这些对比也可以从侧面看出,目前所有的主流浏览器都已经支持WebAssembly V1(Node >= 8.0.0).

与JavaScript做对比

我自己在一个用create-react-app新建的项目中,分别对比了WebAssembly版本和原生JavaScript版本的递归无优化的Fibonacci函数,下图是这两个函数在值是45、48、50的时候的性能对比。

看图说话,这就是WebAssembly与JavaScript很实际的一个性能对比。几乎稳定的是JavaScript的两倍。

WebAssembly在大型项目中的应用

在这里能够举的例子还是很多,比如AutoCAD、GoogleEarth、Unity、Unreal、PSPDKit、WebPack等等。拿其中几个来简单说一下。

AutoCAD

这是一个用于画图的软件,在很长的一段时间是没有Web的版本的,原因有两个,其一,是Web的性能的确不能满足他们的需求。其二,在WebAssembly没有面世之前,AutoCAD是用C++实现的,要将其搬到Web上,就意味着要重写他们所有的代码,这代价十分的巨大。

而在WebAssembly面世之后,AutoCAD得以利用编译器,将其沉淀了30多年的代码直接编译成WebAssembly,同时性能基于之前的普通Web应用得到了很大的提升。正是这些原因,得以让AutoCAD将其应用从Desktop搬到Web中。

Google Earth

Google Earth也就是谷歌地球,因为需要展示很多3D的图像,对性能要求十分高,所以采取了一些Native的技术。最初的时候就连Google Chrome浏览器都不支持Web的版本,需要单独下载Google Earth的Destop应用。而在WebAssembly之后呢,谷歌地球推出了Web的版本。而据说下一个可以运行谷歌地球的浏览器是FireFox。

Unity和Unreal游戏引擎

这里给两个油管的链接自己体验一下,大家注意上网的方式。

  • Unity WebGL的戳这里
  • Unreal引擎的戳这里

WebAssembly要取代JavaScript?

答案是否定的,请看下图。

大家可以看到这是一个协作关系。WebAssembly是被设计成JavaScript的一个完善、补充,而不是一个替代品。WebAssembly将很多编程语言带到了Web中。但是JavaScript因其不可思议的能力,仍然将保留现有的地位。

什么时候使用WebAssembly?

说了这么多,我到底什么时候该使用它呢?总结下来,大部分情况分两个点。

  • 对性能有很高要求的App/Module/游戏
  • 在Web中使用C/C++/Rust/Go的库
    举个简单的例子。如果你要实现的Web版本的Ins或者Facebook, 你想要提高效率。那么就可以把其中对图片进行压缩、解压缩、处理的工具,用C++实现,然后再编译回WebAssembly。

WebAssembly的几个开发工具

  • AssemblyScript。支持直接将TypeScript编译成WebAssembly。这对于很多前端同学来说,入门的门槛还是很低的。
  • Emscripten。可以说是WebAssembly的灵魂工具不为过,上面说了很多编译,这个就是那个编译器。将其他的高级语言,编译成WebAssembly。
  • WABT。是个将WebAssembly在字节码和文本格式相互转换的一个工具,方便开发者去理解这个wasm到底是在做什么事。

WebAssembly的意义

在我的个人理解上,WebAssembly并没有要替代JavaScript,一统天下的意思。我总结下来就两个点。

  • 给了Web更好的性能
  • 给了Web更多的可能
    关于WebAssembly的性能问题,之前也花了很大的篇幅讲过了。而更多的可能,随着WebAssembly的技术越来越成熟,势必会有更多的应用,从Desktop被搬到Web上,这会使本来已经十分强大的Web更加丰富和强大。

WebAssembly实操

要进行这个实际操作,你需要安装上文提到过的编译器Emscripten,然后按照这个步骤去安装。以下的步骤都默认为你已经安装了Emscripten。

WebAssembly在Node中的应用

导入Emscripten环境变量

进入到你的emscripten安装目录,执行以下代码。

source emsdk/emsdk_env.sh
新建C文件

用C实现一个求和文件test.c,如下。

int add(int a, int b) {
	return a + b;
}
使用Emscripten编译C文件

在同样的目录下执行如下代码。

emcc test.c -Os -s WASM=1 -s SIDE_MODULE=1 -o test.wasm

emcc就是Emscripten编译器,test.c是我们的输入文件,-Os表示这次编译需要优化,-s WASM=1表示输出wasm的文件,因为默认的是输出asm.js,-s SIDE_MODULE=1表示就只要这一个模块,不要给我其他乱七八糟的代码,-o test.wasm是我们的输出文件。

编译成功之后,当前目录下就会生成test.wasm

编写在Node中调用的代码

新建一个js文件test.js。代码如下。

const fs = require('fs');
let src = new Uint8Array(fs.readFileSync('./test.wasm'));
const env = {
	memoryBase: 0,
	tableBase: 0,
	memory: new WebAssembly.Memory({
		initial: 256
	}),
	table: new WebAssembly.Table({
		initial: 2,
		element: 'anyfunc'
	}),
	abort: () => {throw 'abort';}
}
WebAssembly.instantiate(src, {env: env})
.then(result => {
	console.log(result.instance.exports._add(20, 89));
})
.catch(e => console.log(e));
执行test.js

运行以下代码。

node test.js

然后就可以看到输出的结果109了。

WebAssembly在React当中的应用

通过fetch的方法调用

直接用fetch的方式。大概的调用方式如下。

const fibonacciUrl = './fibonacci.wasm';
const {_fibonacci} = await this.getExportFunction(fibonacciUrl);

getExportFunction具体代码如下。

getExportFunction = async (url) => {
    const env = {
      memoryBase: 0,
      tableBase: 0,
      memory: new WebAssembly.Memory({
        initial: 256
      }),
      table: new WebAssembly.Table({
        initial: 2,
        element: 'anyfunc'
      })
    };
    const instance = await fetch(url).then((response) => {
      return response.arrayBuffer();
    }).then((bytes) => {
      return WebAssembly.instantiate(bytes, {env: env})
    }).then((instance) => {
      return instance.instance.exports;
    });
    return instance;
};
通过import C文件来调用

先通过Import的方式来引进依赖。

import wasmC from './add.c';

然后进行调用。具体的方式如下。

wasmC({
  'global': {},
  'env': {
    'memoryBase': 0,
    'tableBase': 0,
    'memory': new WebAssembly.Memory({initial: 256}),
    'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'})
  }
}).then(result => {
  const exports = result.instance.exports;
  const add = exports._add;
  const fibonacci = exports._fibonacci;
  console.log('C return value was', add(2, 5643));
  console.log('Fibonacci', fibonacci(2));
});

cesium 源码分析 worker与webassmbly

写在后面

如今技术出现的越来越多,但是实际上在工作中能够用到的,越并不是那么多。其实很多大厂所输出的一些技术,都是有业务场景的,有业务做推动。而不是凭空造轮子。所以总结下来适合自己的才是最好的。当然不是说不要了解新技术,了解新技术跟上步伐是十分必要的。我们现在不用,不代表不需要了解。相反,以后再遇到类似的业务场景时,我们就会多一种选择,可以更加从容的对待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1152908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 环境下 安装 Elasticsearch 7.13.2

Linux 环境下 安装 Elasticsearch 7.13.2 前言镜像下载(国内镜像地址)解压安装包修改配置文件用 Es 自带Jdk 运行配置 Es 可被远程访问然后启动接着启动本地测试一下能不能连 Es 前言 借公司的 centos 7 服务器,搭建一个 Es,正好熟…

8.3 矢量图层点要素单一符号使用五

文章目录 前言单一符号(Single symbol)渲染几何生成器(Geometry generator)QGis代码实现 总结 前言 上一篇教程介绍了矢量图层点要素单一符号中填充标记的用法本章继续介绍单一符号中各种标记的用法说明:文章中的示例…

AR的光学原理?

AR智能眼镜的光学成像系统 AR眼镜的光学成像系统由微型显示屏和光学镜片组成,可以将其理解为智能手机的屏幕。 增强现实,从本质上说,是将设备生成的影像与现实世界进行叠加融合。这种技术基本就是通过光学镜片组件对微型显示屏幕发出的光线…

java项目之中学校园网站(ssm框架)

项目简介 中学校园网站实现了以下功能: 管理员:个人中心、教师管理、学生管理、校园概况管理、名师风采管理、校园公告管理、试卷管理、试题管理、校园论坛、系统管理、考试管理。教师:个人中心、校园概况管理、名师风采管理、校园公告管理…

PM866 3BSE050200R1 L003748-AR 3BSX108237R300

PM866 3BSE050200R1 L003748-AR 3BSX108237R300 工业自动化制造商和工业物联网工具开发商Opto 22宣布推出新版groov,将IIoT technologies MQTT和OPC-UA驱动程序直接嵌入其工业边缘设备。新版本添加到用于web和移动可视化的groov View软件以及开源的Node-RED开发环境…

第三方支付预付卡业务详解

第三方支付预付卡业务详解 第三方支付预付卡业务是指由第三方支付公司提供的一种预先充值后消费的支付方式。用户可以在第三方支付平台上购买预付卡,然后在指定的商户或者服务提供商那里进行消费。 运作模式: 1. 用户在第三方支付平台购买预付卡&#xf…

Django项目单字段的区间查询

在Django项目中会碰到一些需求就是查询某个表中的一些字段从某日到某日的数据,而且是对但字段查询这个时候我们有两两种方法解决 单字段类型是DateTimeField的 查询日期范围的 这个时候在filter.py里面重写DateTimeFromToRangeFilter,为什么要重写呢&am…

kubernetes部署(web界面)

基本队对象 pod 最小单位 service 跟网络相关 Volume Namespace 准备工作: master node1 node2 修改主机名: 做本地解析 10.0.0.51 master 10.0.0.56 node-1 10.0.0.186 node-2 关闭swap分区: swapoff -a  临时关闭 …

双点双向重发布解决方案

某公司有两张园区网络,分别是A园区和B园区,由于业务需求,需要将两张园区网络整合到一起,实现互联互通。 因此管理员将AR2-AR4、AR3-AR5通过物理线缆相连,并且此互联链路运行在ospf 100中。 现在要求工程师在AR2和AR3…

AD教程(三)IC类元件模型的创建

AD教程(三)IC类元件模型的创建 IC类元件 IC芯片(Intergrated Circuit Chip)是将大量的微电子元器件(晶体管、电阻、电容等)形成的集成电路放在一块塑基上,做成一块芯片。 IC类元件的创建 新…

JAVA发票管理的收货单订单创建发票详情介绍

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》作者 公众号:山峯草堂,非技术多篇文章,专注于天道酬勤的 Java 开发问题、中国国学、传统文化和代码爱好者的程序人生,…

用十万字讲明白linux和java的零复制技术

linux I/O 读写方式 Linux提供了轮询、I/O中断以及DMA传输这3种磁盘与主存之间的数据传输机制。 轮询方式是基于死循环对 I/O 端口进行不断检测。 I/O中断方式 I/O 中断方式是指当数据到达时,磁盘主动向 CPU 发起中断请求,由 CPU 自身负责数据的传输…

10.31一些代码分析,香浓展开,移位器(桶形多位),二进制转格雷码

always的block之间,采用并行执行 always之内,采用非阻塞赋值,为顺序执行 一些代码分析 这个把使能信号和W信号组合在一起,进行case语句,即只有合并信号最高位为1时,才进行操作 always后面要写&#xff0…

springboot大学生就业推荐系统 毕业设计-附源码01535

摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对学生就业管理等问题,对学生就业…

关于脉冲发生器,你知道多少?

01 引言 脉冲发生器(Pulse Generator,PG)是产生脉冲信号的专用仪器。它可以生成具有特定频率、幅值和脉冲宽度的脉冲信号,常用于各种科学、工程和技术领域中的实验、测试、通信和控制应用。 那么,对于一台脉冲发生器…

SDH传输分析仪有什么用? TFN D300S SDH传输分析仪详解

数字传输分析仪是数字通信中最重要、最基本的测试仪器,主要用于测试数字通信信号的传输质量,其主要测试参数包括误码、告警、开销、抖动和漂移等,其广泛应用于数字通信设备的研制、生产、维修和计量测试,还可应用于数字通信网络的…

自学VUE笔记

一、基础语法学习 1、Attribute 绑定 a、绑定单个属性&#xff1a;给这个div 增加id 属性 ​ <div v-bind:id"dynamicId"></div>简写&#xff1a; <div :id"dynamicId"></div> b、绑定多个属性值 data() {return {objectOf…

20年经典传承 | 性能圣典!火焰图发明者Brendan Gregg“神作”

20年20本经典畅销书 NO.9 豆瓣评分9.3 性能大师经典巨著 每一个学习性能优化/性能评估的工程师的必备手册 性能测量的水相当深&#xff0c;斯坦福大学的 John Ousterhout 教授在“Always Measure One Level Deeper”一文&#xff08;《ACM 通讯》杂志&#xff0c;2018 年第…

信创强国 | 安全狗荣获信创工委会技术活动单位证书

近日&#xff0c;安全狗荣获中国电子工业标准化技术协会信息技术应用创新工作委员会&#xff08;以下简称“信创工委会”&#xff09;颁发的信息技术应用创新工作委员会技术活动单位证书。 作为国内云原生安全领导厂商&#xff0c;安全狗在信息技术应用创新方面有多年的技术积累…

【教3妹学编辑-算法题】每棵子树内缺失的最小基因值

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开发。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;阳光明媚、万里无云、秋高气爽&#xff0c;适合秋游。 2哥&#x…