1.前言

参加完2018年上海的QCon大会,想到了会议中来自Microsoft的朱力旻大佬讲的WebAssembly,感触颇深。

我之前完全没有了解过WebAssembly,之前没有了解的原因也很简单,没有什么实际的应用场景,但工欲善其事,必先利其器。

抱着这样的想法,便开始入坑WebAssembly。

2.Why WebAssembly

2.1 javascript的背景

JavaScript这门由Brendan Eich花了10天创造出来的语言,在如今收到了广泛的应用,同时也因为其缺陷遭受到了业界的一些诟病。的确,这门被仓促的创造出来的语言有很多缺陷。毕竟JavaScript结合了函数式编程和面向对象编程,在JavaScript之前的参考极少。

并且JavaScript发展过于迅速,没有多少时间去调整标准。比如JavaScript的变量是一个动态变量。上一秒这个变量可以是Array,下一秒就变成了一个Number。

JavaScript的语法太过于灵活,这样导致JavaScript在开发大型应用上成为了瓶颈,并且类似于CAD这种网格模型对于性能要求特别高的情况下,JavaScript根本无法胜任。

2.2 社区的补救

例如,微软给出了TypeScript这个解决方案,TypeScript为JavaScript添加了静态类型检查,提升了代码的健壮性。但是最终TypeScript还是要编译成JavaScript来运行。

于是在2013年,为了推动Web性能的发展。WebAssembly的前身asm.js诞生了。下面给个例子。

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

传统的JavaScript的动态变量需要在代码执行的时候,编译器才知道当前变量的类型。我们都知道"use strict",这是JavaScript的严格模式。

通过添加代码 "use strict"来使用严格模式。在严格模式下的JavaScript代码会通过抛出错误的方式来代替原来的静默错误。并且在某些情况下, 严格模式下的代码运行效率会高于"sloppy mode"下的代码。

而上述代码中的"use asm",就是告诉引擎,下面的代码是asm.js的代码。当引擎看到"0 | 0",就会在这行代码运行之前知道,这是一个整形的数据,而不会再去编译一次。而看到"+1.1"就会知道这是一个浮点型的数据。asm.js是JavaScript的一个子集。

并且将JavaScript的动态变量变成了静态变量,代码在运行时,有接近原生的性能。

可能到这里疑问就来了,既然asm.js在运行时已经有了接近native的性能。为什么还会出现WebAssembly这个技术。那是asm.js并不能解决所有的问题。

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

为什么说asm.js不能解决所有的问题?拿Microsoft Edge的Javascript引擎举个例子。

上面这张图是ChakraCore引擎的结构。Chakra是Microsoft Edge浏览器开源的Chakra Javascript引擎的核心部分。我们在浏览器中运行的Javascript代码首先会经过编译,解析成AST(AKA抽象语法树),想实操的可以去这里试试。

asm.js及时让其运行性能接近了native,但是仍然需要经过parser这一步。而这一步是整个过程中最费时的一步。这就给asm.js造成了一个瓶颈。

2.4 WebAssembly横空出世

于是2015年,WebAssembly出现了。WebAssembly是一个可移植、体积小、加载快并且即兼容Web的汇编格式。

与asm.js类似的是,WebAssembly拥有静态类型。同时也是编译目标,并且可移植。而不同于asm.js,WebAssembly是汇编格式,代码量小,起步相对较快。而且语法上完全脱离JavaScript。这是WebAssembly官方给出的一个demo,可以去体验一下。

3 WebAssembly快速入门

WebAssembly为什么说是编译的目标。是因为WebAssembly可以将C和C++编译成WebAssembly,用的工具是Emscripten,是一个预编译工具。要进行WebAssembly的编译,需要安装git、cmake、python

假设你是在mac上进行操作的。

3.1 安装

安装WebAssembly工具链。

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --build=Release sdk-incoming-64bit binaryen-master-64bit

可能会等的有点久,并且可能会出现cmake没有安装的报错信息。可以使用homebrew安装cmake后,再执行安装操作。

3.2 设置环境变量

在emsdk目录下,运行下列命令。就可以在当前的终端窗口中运行emcc命令了。

source ./emsdk_env.sh --build=Release

3.3 编写C或者C++文件

新建一个C文件,代码如下。

#include <stdio.h>

long factorial(int num) {
if (num <= 0) return 1;
else {
return num * factorial(num - 1);
}
} int main () {
int num = factorial(10);
printf("The Result: %d \n", num);
}

3.4 利用Emscripten编译代码

然后在相同目录下执行emcc的编译命令,该命令会将C或者C++文件编译成wasm模块。

emcc hello.c -s WASM=1 -o hello.html

其中,hello.c为源文件,-o hello.html是这个命令的输出文件,-s WASM指定输出的格式为wasm,并且版本为1。执行这个文件后,会在目录下生成如下数据。

.
├── hello.c
├── hello.html
├── hello.js
└── hello.wasm

hello.wasm就是经过编译后的C代码的二进制文件。而hello.js则是C语言与JavaScript相互转化的中间代码。执行下面的代码就可以在localhost的8080端口看到我们的C模块在前端的调用和展示。

emrun --no_browser --port 8080 .

然后就可以在浏览器中看到如下的输出。

我们编写的C模块已经可以在浏览器中正常的运行了。这说明我们的WebAssembly编译成功了。

4 在前端项目中使用Wasm

可以参考这篇文章,如何在React项目中直接使用WebAssembly,在这篇文章的项目中可以看到完整的从wasm文件中提取出函数的function,以及清晰的用C实现的函数和用JavaScript实现的函数的运行性能对比。

参考资料

初探WebAssembly的更多相关文章

  1. emscripten、 WebAssembly,传递字符串给c函数

    下面看具体的实例. 下面的代码是一个C函数,实现简单的字符串拼接,然后返回拼接的字符串. #include <stdio.h> #include <string>  char* ...

  2. 【webAssembly系列】webAssembly初探究竟

    一.前言 自从JavaScript诞生开始,到现在开始变成流行的编程语言,背后的是web发展所推动的.web应用的变得更多更复杂,但是渐渐暴露出JavaScript的问题: (1)语法太灵活导致开发大 ...

  3. ASP.NET Core Blazor 初探之 Blazor WebAssembly

    最近Blazor热度很高,传说马上就要发布正式版了,做为微软脑残粉,赶紧也来凑个热闹,学习一下. Blazor Blazor是微软在ASP.NET Core框架下开发的一种全新的Web开发框架.Bla ...

  4. ASP.NET Core Blazor 初探之 Blazor Server

    上周初步对Blazor WebAssembly进行了初步的探索(ASP.NET Core Blazor 初探之 Blazor WebAssembly).这次来看看Blazor Server该怎么玩. ...

  5. ASP.NET Core Blazor Webassembly 之 组件

    关于组件 现在前端几大轮子全面组件化.组件让我们可以对常用的功能进行封装,以便复用.组件这东西对于搞.NET的同学其实并不陌生,以前ASP.NET WebForm的用户控件其实也是一种组件.它封装ht ...

  6. ASP.NET Core Blazor Webassembly 之 路由

    web最精妙的设计就是通过url把多个页面串联起来,并且可以互相跳转.我们开发系统的时候总是需要使用路由来实现页面间的跳转.传统的web开发主要是使用a标签或者是服务端redirect来跳转.那今天来 ...

  7. 初探领域驱动设计(2)Repository在DDD中的应用

    概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...

  8. CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探

    CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...

  9. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

随机推荐

  1. 【2019雅礼集训】【CF 960G】【第一类斯特林数】【NTT&多项式】permutation

    目录 题意 输入格式 输出格式 思路 代码 题意 找有多少个长度为n的排列,使得从左往右数,有a个元素比之前的所有数字都大,从右往左数,有b个元素比之后的所有数字都大. n<=2*10^5,a, ...

  2. HBASE强制删除表

    1,先把hdfs的对应表的数据删除 hadoop fs -mv /hbase/<table_name> /tmp 2,修复meta信息 hbase hbck -fixMeta -fixAs ...

  3. Python数据科学手册

    Python数据科学手册(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1KurSdjNWiwMac3o3iLrzBg 提取码:qogy 复制这段内容后打开百度网盘手 ...

  4. Round #3

    题源:感谢 by hzwer 水灾(sliker.cpp/c/pas) 1000MS  64MB 大雨应经下了几天雨,却还是没有停的样子.土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的 ...

  5. MVCAPi Httpclient

    APi配制文件 删除修改api 显示和命名空间 新增

  6. Java-JSON 解析

    JSON  JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采 ...

  7. 关于 js中replace 特殊符号 ‘.’ 的问题

    问题: 字符串转数组,但是分割点在‘.’ ,需要保留每个后缀的 ‘.’ + 类型 解决: let videoType = '.avi.rmvb.rm.asf.divx.mpg.mpeg.mpe.wmv ...

  8. OO第一次博客作业

    OO第一次博客作业 一.三次作业的bug反省 1.自己发现别人的问题 (1)输入处理的问题,比如第一次作业,主要就是处理输入的字符串,然后有同学的正则表达式有问题,则对于一些错误输入就不能正确判断. ...

  9. Ajax实现带进度条的文件上传

    Ajax实现带进度条的文件上传 文件上传页面运行效果 上传文件并显示进度条运行效果 代码如下; DiskFileItemFactory factory = new DiskFileItemFactor ...

  10. 数据调试~~TCP转串口、串口转TCP调试

    Android socket开发了一个socket客户端,当输入服务器ip以及端口,建立连接之后,Android可以发送数据到电脑接收服务器端. 如果电脑端没有socket服务器怎么办?方法如下: 1 ...