初探WebAssembly
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的更多相关文章
- emscripten、 WebAssembly,传递字符串给c函数
下面看具体的实例. 下面的代码是一个C函数,实现简单的字符串拼接,然后返回拼接的字符串. #include <stdio.h> #include <string> char* ...
- 【webAssembly系列】webAssembly初探究竟
一.前言 自从JavaScript诞生开始,到现在开始变成流行的编程语言,背后的是web发展所推动的.web应用的变得更多更复杂,但是渐渐暴露出JavaScript的问题: (1)语法太灵活导致开发大 ...
- ASP.NET Core Blazor 初探之 Blazor WebAssembly
最近Blazor热度很高,传说马上就要发布正式版了,做为微软脑残粉,赶紧也来凑个热闹,学习一下. Blazor Blazor是微软在ASP.NET Core框架下开发的一种全新的Web开发框架.Bla ...
- ASP.NET Core Blazor 初探之 Blazor Server
上周初步对Blazor WebAssembly进行了初步的探索(ASP.NET Core Blazor 初探之 Blazor WebAssembly).这次来看看Blazor Server该怎么玩. ...
- ASP.NET Core Blazor Webassembly 之 组件
关于组件 现在前端几大轮子全面组件化.组件让我们可以对常用的功能进行封装,以便复用.组件这东西对于搞.NET的同学其实并不陌生,以前ASP.NET WebForm的用户控件其实也是一种组件.它封装ht ...
- ASP.NET Core Blazor Webassembly 之 路由
web最精妙的设计就是通过url把多个页面串联起来,并且可以互相跳转.我们开发系统的时候总是需要使用路由来实现页面间的跳转.传统的web开发主要是使用a标签或者是服务端redirect来跳转.那今天来 ...
- 初探领域驱动设计(2)Repository在DDD中的应用
概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...
- CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探
CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...
- 从273二手车的M站点初探js模块化编程
前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...
随机推荐
- W3C的标准到底是啥?
1.图片的alt="" 属性必须每张图片都加上,而且对齐属性用CSS来定义.不加不能通过XHTML 1.0的验证. 2.每个文档必须加上DTD声明. a) !DOCTYPE htm ...
- mysql错误:The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement解决方法
本文为大家讲解的是mysql错误:The MySQL server is running with the --skip-grant-tables option so it cannot execut ...
- 使用Spring Aop自定义注解实现自动记录日志
百度加自己琢磨,以下亲测有效,所以写下来记录,也方便自己回顾浏览加深印象之类,有什么问题可以评论一起解决,不完整之处也请大佬指正,一起进步哈哈(1)首先配置文件: <!-- 声明自动为sprin ...
- echarts-for-react 从新渲染数据
<ReactEcharts option={option} notMerge={true} style={{height: '600px', width: '100%'}} className ...
- C# CSV 文件转换成DataTable
{ DataTable dt = new DataTable(); FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess ...
- Java for Andriod 第二周学习总结
第四章 学习时遇到的问题或新知识点: 1. 构造方法.每个类至少有一个构造方法,且构造方法必须的名称必须与类名相同. 2. Varargs.允许方法拥有一个可变长度的参数列表. 3. 对象的内存分配. ...
- javascript 编程风格 部分精要
1 换行保持两个缩进(通常是一行太长) 运算符前后加一个空格,包括赋值运算符和逻辑运算符 括号运算符,左括号之后,右括号之前不应该有空格 段代码无关,添加空行 命名驼峰式,一般首字母小写,其他单词首字 ...
- cadence网络表解读及导入
绘制完成原理图,并且通过了DRC检验之后,需要创建和导入网络表,下面网络表内容做简单总结.
- [Swift]LeetCode629. K个逆序对数组 | K Inverse Pairs Array
Given two integers n and k, find how many different arrays consist of numbers from 1 to n such that ...
- [Swift]LeetCode922.按奇偶排序数组 II | Sort Array By Parity II
Given an array A of non-negative integers, half of the integers in A are odd, and half of the intege ...