|
1. 前言WebAssembly 是 W3C 标准化组织制定的一个可移植、体积小、加载快并且兼容 Web 的全新格式。利用 WebAssembly 技术可以方便地将非 JavaScript 代码快速地“运行”在浏览器中,从而为前端场景提供了无限可能;此外,随着 WebAssembly 在开发者社区中越来越流行,也正在成为服务端以及云计算平台上的新锐。作为本课程的开篇,本文首先介绍 WebAssembly 的发展历程,正所谓 "以史为镜,可以知兴替",从其历史演变中我们可以深入了解 WebAssembly 技术的来龙去脉,以及它的核心诉求和价值;接下来,我们会梳理和总结 WebAssembly 的使命和优势;最后,我们通过一个简单的 WebAssembly 浏览器应用示例,带领读者一起身临其境地感受下 WebAssembly 在 Web 环境中的真实使用体验。2. WebAssembly 历史演变WebAssembly 技术源于浏览器,其发展历程可以说是一部浏览器性能优化史。在 Web 前端领域,JavaScript 语言是编写运行在浏览器上的 Web 应用的首选;与此同时,Node.js 等非浏览器 JavaScript 运行时环境的出现, JavaScript 变得越来越流行;然而,各类应用随着功能逐渐复杂化,对性能的要求越来越高;而由于 JavaScript 语言本身的一些特性,已经很难满足日益增长的应用性能需求。为了满足应用日益增长的性能需求,针对 JavaScript 语言本身缺陷带来的瓶颈优化,逐步形成了三个阶段性优化产物,他们分别是 asm.js、NaCl/PNaCl 以及 WebAssembly,正是这三个阶段的优化逐步推动了 WebAssembly 技术的发展。接下来,我们将逐一从这三个阶段来阐述其各自的诉求及其价值,从而了解 WebAssembly 起源及其目标和优势。2.1 asm.js 阶段JavaScript 是前端开发的首选语言,由于 JavaScript 本身是一种动态、弱类型编程语言;因此,只有在程序运行时才能确定执行上下文中对象具体数据类型;不仅如此,JavaScript 语言还允许同一个变量在不同时刻可以绑定不同类型的对象。JavaScript 的弱类型导致虚拟机只能在执行时刻进行类型推断,同时,其动态性又进一步导致当前的执行结果无法被复用,因为代码所执行的对象类型和逻辑都可能随时改变。为了解决 JavaScript 语言自身带来的上述弊端,asm.js 便应运而生。asm.js 设计的出发点直指 JavaScript 语言的设计缺陷,asm.js 可以在 JavaScript 代码运行之前便确定程序中变量的具体类型;与此同时,它还进一步保证程序中变量的类型不会在程序运行的过程中发生改变。基于 asm.js 对弱类型和动态性的约束,虚拟机在执行过程中可以利用确定性的类型进行编译优化,并且编译结果可以复用而不需要重复执行相同源代码的编译优化过程,从而使得 Web 应用的运行效率有巨大的提升。asm.js 标准始于 2013 年 8 月,它是 JavaScript 的一个严格子集, 是一种可用于编译器的低层级的、高效的目标语言。相较 JavaScript 而言,asm.js 使用了一 种名为 Annotation 的类型声明方式来对变量类型进行约束,其中 Annotation 的形式采用 | T 表示。如下述 asm.js 模块代码所示,赋值语句 n = n | 0 通过对变量与 0 进行使用"按位或"操作的声明方式,可以让虚拟机在解析 asm.js 代码时强制将该变量 n 视为一个 32 位的整数,并且该变量所能够存储的数据类型在运行过程中无法被更改。functionfast_fib_module(stdlib,foreign,heap){"useasm";functionfib(n){n=n|0;if(n>>>0=limit)break;++iteration;}//Doafewextraiterationsforquickescapestoreduceerrormarginwhile(iteration1.0){letfrac=Math.log2(0.5*Math.log(sqd));col=((NUM_COLORS-1)*clamp((iteration+1-frac)*invLimit,0.0,1.0));}store(stride+(x<<1),col);}}/**Clampsavaluebetweenthegivenminimumandmaximum.*/@inlinefunctionclamp(value:T,minValue:T,maxValue:T):T{returnmin(max(value,minValue),maxValue);}为了展示 Mandelbrot 效果,可以通过在 Web 页面[11] 中来加载 Mandelbrot.wasm,并调用 computeLine 函数来计算 Mandelbrot 集来完成图形绘制。//file:index.html//Setupthecanvaswitha2Drenderingcontextvarcnv=document.getElementsByTagName("canvas")[0];varctx=cnv.getContext("2d");varbcr=cnv.getBoundingClientRect();//Computethesizeoftheviewport//varwidth=bcr.width|0;//varheight=bcr.height|0;//varratio=window.devicePixelRatio||1//...//ctx.scale(ratio,ratio);//Computethesizeofandinstantiatethemodule'smemoryconstmemory=newWebAssembly.Memory({initial(byteSize+0xffff)&~0xffff)>>>16});constmem=newUint16Array(memory.buffer);constimageData=ctx.createImageData(width,height);constargb=newUint32Array(imageData.data.buffer);//Fetchandinstantiatethemodulefetch("build/Mandelbrot.wasm").then(response=>response.arrayBuffer()).then(buffer=>WebAssembly.instantiate(buffer,{env:{memory,"Math.log":Math.log,"Math.log2":Math.log2},})).then(module=>{constexports=module.instance.exports;constcomputeLine=exports.computeLine;constupdateLine=function(y){varyx=y*width;for(letx=0;x{alert("FailedtoloadWASM:"+err.message+"(adblocker,maybe)");console.log(err.stack);});按上述步骤,我们已经生成 Mandelbrot.wasm 二进制模块,并在 index.html 中完成模块加载和图形绘制的逻辑实现,最后,我们可以在本地建立 http 服务来加载和展示 Mandelbrot 图形效果,如图 3 所示。cd$webassembly_tech/samples/mandelbrotnpxserve>┌──────────────────────────────────────────┐>│Serving!│>││>│-Local:http://localhost:3000│>││>│Copiedlocaladdresstoclipboard!│>││>└──────────────────────────────────────────┘图 3. Mandelbrot 集图形效果虽然上述步骤中,我们已经详细描述了 Mandelbrot Web 应用中 WebAssembly 的生成和 Web 页面集成的各个步骤;但为了方便读者构建原型,webassembly_tech [11] 提供了源代码的下载,并提供了 Mandelbrot 项目使用文档快速构建和查看效果。5. 总结至此,我们已经完整地介绍了 WebAssembly 技术的来龙去脉以及它的核心价值,并通过 Mandelbrot 示例带领读者一起身临其境地感受了 WebAssembly 在 Web 环境中的真实使用体验。然而,随着 WebAssembly 技术的不断发展,其应用领域和应用场景也越来越广阔,为了更好的了解 WebAssembly 的价值及其应用生态,在接下来的第二章中,我们将会对 WebAssembly 使用场景和未来发展趋势做进一步的介绍和探索。6. 参考文献[1]. "asm.js" Working Draft: http://asmjs.org/spec/latest/[2]. Native Client (NaCl & PNaCl): https://www.chromium.org/nativeclient/[3]. WebAssembly: https://webassembly.org/specs/[4]. Bringing WebAssembly outside the web with WASI by Lin Clark: https://www.youtube.com/watchv=fh9WXPu0hw8[5]. Mandelbrot set: https://en.wikipedia.org/wiki/Mandelbrot_set[6]. Local Web Server: https://github.com/yaozhongxiao/cli/tree/master/server[7]. webassembly_tech: https://github.com/yaozhongxiao/webassembly_tech/tree/master/samples[8]. Mandelbrot set: https://en.wikipedia.org/wiki/Mandelbrot_set[9]. AssemblyScript: https://www.assemblyscript.org/[10]. Mandelbrot Set:https://github.com/yaozhongxiao/webassembly_tech/tree/master/samples/mandelbrot/index.html[11]. webassembly_tech: https://github.com/yaozhongxiao/webassembly_tech/tree/master/samples/mandelbrot/README.md点击上方关注 · 我们下期再见点击左下方“阅读原文”,或扫描上方二维码,进入专栏阅读《走进 WebAssembly 的世界》完整版。
|
|