JavaScript 填坑之 flow 和 WebAssembly 技术
js
的坑
作为一门只用了十天时间赶工出来的动态语言, JavaScript
已经做得很好了, 但是有些不得不解决的问题也逐渐暴露出来了. 下面是一些坑列表.
- 运行性能, 由
google
的v8
引擎解决. - 类型继承, 由
ES6
语法糖和phototype
对象构成原型链解决. - 模块化, 由
ES6
的import
和exports
实现. - 全局变量(
window
), 社区方案使用Global
统一替换. - 回调函数机制, 由
promise
解决. - 动态语言导致的大型项目类型检查, 使用
React.PropTypes
和flowjs
, 或者使用TypeScript
. v8
引擎编译性能,WebAssembly
技术.
flowjs
flowjs
是Facebook
为了大型js
项目拥有类型检查而发明的一个库. 使那些需要类型检查的项目不需要使用重量级的TypeScript
的另一个解决方案. 基本作用是通过可选的类型声明, 在写代码时自动检查类型是否匹配. 语法也不会很麻烦, 基本都是在变量后面加上:type
来声明. 但是我看了一圈, 好像没有解构赋值时的类型语法, 这样就有点麻烦了.
1 | /* @flow */ |
v8
引擎
在说WebAssembly
之前, 必须看看v8
引擎的原理和不足. chrome
现在这么高的市场占有率有一半都是靠着v8
引擎的速度取得的.
v8
引擎底层由C++
实现, 可以作为一个独立模块, 被任何C++
应用引用. 如Node.js
框架就是基于v8
引擎. v8
基本功能也是编译, 执行js
代码, 管理内存, 负责垃圾回收, 与宿主语言交互等功能. 而这种运行时编译的语言都存在一个问题, 即类型改变. v8
中编译技术为JIT
(Just in time compiling), JIT
基于运行期分析编译, 而JavaScript
是一个没有类型的语言, 于是大部分时间, JIT
编译器其实是在猜测JavaScript
中的类型, 如开始一个函数执行的是add(1,1)
, 那么JIT
会将它编译成add(int a,int b)
来执行, 并保存, 但如果下次调用add('a','b')
, 那么JIT
则需要重新编译一遍. 在js
这种动态类型的情况下, 一个函数会发生很多次编译, 重新编译开销又非常大, 这便是v8
或者说js
引擎无法避免的问题. Google
也发明过声明, 认为js
是一门天生残疾的语言, 然后就不再继续发力v8
虚拟机了. v8
其实已经事实上代表了js
能达到的运行时性能顶峰, 而Google
也认为基于这种动态类型无法再继续提升虚拟机性能了.
asm.js
asm
是mozilla
提出的一个解决方案, 和js
语法相同, 只是在火狐浏览器中会特别解析语法, 直接编译成机器语言, 极大的加快执行速度. 但是存在的一个问题是浏览器支持率并不高, 而且也不是官方解决方案.
WebAssembly
这时候, 几大浏览器厂家(Mozilla
, Google
, Microsoft
, Apple
)觉得这种思路还是可以的, 那么就升级一下, 变为WebAssembly
技术. 这种技术基本等于浏览器执行原生代码. 和Java
调用JNI
一样的速度.
start
在非开发版的浏览器中, Firefox
对WebAssembly
支持比较好, 在浏览器控制台中粘贴以下代码, 如果可以运行而且不报错, 说明支持WebAssembly
.
1 | WebAssembly.compile(new Uint8Array(` |
WebAssembly
有明确的数据类型, 上面函数运行时传入参数应该为int 32
类型, 不过如果传其他值会被动态转换, 所以add('2',3) = 5
, add('2',{a:1}) = 2
. 但是不推荐这样使用, 因为具体会转换成什么不能确定, 通常是0
.
编译C/C++
到WebAssembly
使用WebAssembly
技术, 肯定不能直接写二进制代码, 否则为什么要用js
. WebAssembly
一般都是由其他语言编译过来, 如C/C++
等. 网上有个在线工具可以查看WasmExplorer, 生成的wast
文件可以转换成wasm
文件并下载下来.
先写一段C
代码, 然后执行emcc demo.c -Os -s WASM=1 -s SIDE_MODULE=1 -o demo.wasm
, 即可生成wasm
文件.
执行wasm
文件
执行wasm
目前只有一种方法, 即通过javascript
. 官网文档里也有提供初略的例子.
1 | //demo.c |
asm.js
编译成WebAssembly
asm.js
既然是带类型的js
, 那么也可以生成WebAssembly
文件. 官方有提供工具Binaryen
和WABT (WebAssembly Binary Toolkit)
. 流程基本是由js
生成wast
文件, 再转换成wasm
文件.
WebAssembly
调用JavaScript
目前来说, 调用方法还是比较麻烦的, 需要将调用的函数通过imports
参数传入模块中, 而且需要在wast
文件中, 添加import
和调用call
方法才可以执行. 期待以后简单点的写法互相调用, 那么就可以实现任何语言来写js
代码了, 而且运行速度将大大加快.
JavaScript 填坑之 flow 和 WebAssembly 技术
https://mosby-zhou.github.io/2017/11-16-flowjs-and-webassembly/