当前位置: 首页 > Web前端 > HTML

WebAssembly及其API的完整介绍

时间:2023-04-02 14:55:09 HTML

作者:MahdhiRezvi译者:前端小智来源:medium优质视频教程福利一:http://www.longstudy.club/tui...如何搭建一个服务器博客:http://www.longstudy.club/tui...点赞再看,微信搜索【大千世界】关注此人,没有大厂背景,却有积极的态度。本文已收录到GitHubhttps://github.com/qq44924588...,文章已分类,也整理了很多我的文档和教程资料。自从引入计算机以来,本机应用程序的性能得到了极大的提高。相比之下,Web应用程序非常慢,因为JS最初并不是为了速度而构建的。但是由于浏览器之间的激烈竞争,以及V8等JS引擎的快速发展,JS可以在机器上快速运行。但它仍然无法击败本机应用程序的性能。这主要是因为JS代码要经过几个过程才能生成机器码。随着WebAssembly的引入,现代网络发生了革命性的变化,这是一种速度非常快的技术。让我们来看看WebAssembly是什么以及它如何与JS集成以构建快速应用程序。什么是WebAssembly?在学习WebAssembly之前,我们先了解一下Assembly是什么。汇编是一种低级编程语言,与体系结构的机器级指令密切相关。换句话说,只需要一个过程就可以转换为机器可以理解的代码,称为机器码。这个转换过程称为组装。WebAssembly可以简称为web的组装。它是一种低级类汇编语言,具有紧凑的二进制格式,使您能够以类似本机的速度运行Web应用程序。它还为C、C++和Rust等语言提供编译目标,使客户端应用程序能够以接近原生的性能在Web上运行。此外,WebAssembly在这里与JS一起运行,而不是取代它。使用WebAssemblyJavaScriptAPI,您可以交替地从任何一种语言来回运行代码,而不会出现任何问题。这使我们的应用程序能够利用WebAssembly的强大功能和性能以及JS的通用性和适应性。这开辟了一个全新的网络应用程序世界,可以运行最初并非为网络设计的代码和功能。有何不同LinClark预测,2017年WebAssembly的推出可能会引发Web开发生命周期的新转折点。另一个早期的转折点发生在引入JIT时,它使JS快了近10倍。如果你将WebAssembly的编译过程与JS的编译过程进行比较,你会注意到其中有几个过程被剥离,其余的被修剪,如下所示:JIT是一种通过监控运行状态,优化hot代码(重复执行多次的代码)。通过这种方式,JavaScript应用程序的性能可以提高很多倍。仔细对比上图,注意到WebAssembly中的重新参与已经被完全剥离。这主要是因为编译器不需要对WebAssembly代码做任何假设,因为代码中明确提到了数据类型之类的东西。但是JS不是这样的,因为JIT要对代码进行一些假设,如果假设不成立,就需要重新优化它的代码。如何获取WebAssembly代码WebAssembly是一项伟大的技术,我们需要如何利用WebAssembly的强大功能呢?有几种方法:不建议从头开始编写WebAssembly代码,除非你非常了解基础知识从C编译到WebAssembly从C++编译到WebAssembly将Rust编译到WebAssembly使用AssemblyScript将Typescript编译到WebAssembly。对于不熟悉C/C++或Rust的Web开发人员来说,这是支持更多语言选项的不错选择。此外,还有Emscripten和WebAssemblyStudio等工具可以帮助您完成上述过程。用于JS的WebAssemblyAPI为了充分利用WebAssembly的特性,我们必须将其与JS代码集成,这可以借助JavaScriptWebAssemblyAPI来完成。WebAssembly代码的模块编译和实例化驻留在.wasm文件中。该文件应编译为特定于其运行的机器的机器代码。我们可以使用WebAssembly.compile方法编译一个WebAssembly模块。WebAssembly.instantiate方法实例化一个已编译的模块。或者,我们也可以将从.wasm文件中获取的数组缓冲区传递给WebAssembly.instantiate方法。这也有效,因为实例化方法有两个重载。让exportsfetch('sample.wasm').then(response=>response.arrayBuffer()).then(bytes=>WebAssembly.instantiate(bytes)).then(results=>{exports=results.instance.exports})上述方法的缺点之一是这些方法无法直接访问字节码,因此在编译/实例化wasm模块之前需要采取额外步骤将响应转换为ArrayBuffer。相反,我们可以使用WebAssembly.compileStreaming/WebAssembly.instantiateStreaming方法来实现与上述相同的功能,其优点是无需将响应转换为ArrayBuffer即可直接访问字节码。letexportsWebAssembly.instantiateStreaming(fetch('sample.wasm')).then(obj=>{exports=obj.instance.exports})请注意,WebAssembly.instantiate和WebAssembly.instantiateStreaming返回实例以及已编译的模块,它们是可用的快速入门模块的实例。letexports;letcompiledModule;WebAssembly.instantiateStreaming(fetch('sample.wasm')).then(obj=>{exports=obj.instance.exports;//访问编译模块compiledModule=obj.module;})导入对象实例在实例化WebAssembly模块实例时,您可以选择传递一个导入对象,该对象将包含要导入到新创建的模块实例中的值。有4种类型:globalvaluesfunctionsmemorytables您可以将导入对象视为提供给模块实例以帮助其完成任务的工具。如果没有提供导入对象,编译器将分配一个默认值。GlobalWebAssembly.Global对象表示一个全局变量实例,它可以被JavaScript访问并且可导入/导出,并且跨越一个或多个WebAssembly.Module实例。它允许动态链接多个模块。您可以使用WebAssembly.Global()构造函数来创建全局实例。constglobal=newWebAssembly.Global({value:'i64',mutable:true},20)语法varmyGlobal=newWebAssembly.Global(descriptor,value)全局构造函数接受两个参数。descriptorGlobalDescriptor包含一个具有2个属性的表:value:USVString表示全局变量的数据类型。它可以是i32、i64、f32或f64mutable:布尔值确定是否可以修改。默认值为假。Value可以是任意变量值,其类型需要与变量类型匹配。如果未定义变量,则使用0而不是constglobal=newWebAssembly.Global({value:'i64',mutable:true},20);letimportObject={js:{global}};WebAssembly.instantiateStreaming(fetch('global.wasm'),importObject)应该将全局实例传递给importObject,以便可以在WebAssembly模块实例中访问它。内存当WebAssembly模块被实例化时,它需要一个内存对象。您可以创建一个新的WebAssembly.Memory并传递该对象。如果没有创建内存对象,则会在模块实例化并传递给实例时自动创建。JS引擎创建一个ArrayBuffer来执行此操作。ArrayBuffer是JS引用的JavaScript对象。JS为你分配内存。你告诉它需要多少内存,它就会创建一个相应大小的ArrayBuffer。ArrayBuffer做了两件事,一是做WebAssembly内存,二是做JavaScript对象。它使得在JS和WebAssembly之间传递内容变得更加容易。让内存管理更安全。TableWebAssembly.Table()构造函数根据给定的大小和元素类型创建一个Table对象。这是一个Javascript包装器对象,它包装了WebAssembleTable,具有类似数组的结构,并存储了多个函数引用。在JS或WebAssemble中创建的表对象可以同时被JS或WebAssemble访问和更改。引入Table的主要原因是为了提高安全性。我们可以使用set()、grow()和get()方法来操作表。示例为了演示,我将使用WebAssemblyStudio应用程序将C文件编译为.wasm。我在wasm文件中创建了一个函数来计算一个数的幂。我将必要的值传递给函数并接收JavaScript中的输出。同样,我在wasm中进行了一些字符串操作。请注意,wasm没有字符串类型。因此,它将使用ASCII值。返回给JS的值将指向存储输出的内存位置。因为内存对象是一个ArrayBuffer,所以我一直迭代直到接收到字符串中的所有字符。JavaScript文件letexports;letbuffer;(async()=>{letresponse=awaitfetch('../out/main.wasm');letresults=awaitWebAssembly.instantiate(awaitresponse.arrayBuffer());//或//letresults=awaitWebAssembly.instantiateStreaming(fetch('../out/main.wasm'));letinstance=results.instance;exports=instance.exports;buffer=newUint8Array(exports.memory.buffer);findPower(5,3);printHelloWorld();})();constfindPower=(base=0,power=0)=>{console.log(exports.power(base,power));}constprintHelloWorld=()=>{让指针=exports.helloWorld();让海峡=“”;for(leti=pointer;buffer[i];i++){str+=String.fromCharCode(buffer[i]);}console.log(str);}C文件#defineWASM_EXPORT__attribute__((visibility("default")))#includeWASM_EXPORTdoublepower(doublenumber,doublepower_value){returnpow(number,power_value);}WASM_EXPORTchar*helloWorld(){return"helloworld";}应用WebAssembly更适合用于写模块,承接各种对于复杂的计算,比如图像处理、3D计算、语音识别、视音频编解码等,主程序还是需要用javascript写的,可以找我返现15(https://cn.aliyun.com/1111/ho...代码部署后可能存在的bug,无法实时获知,之后为了解决这些bug,花了不少时间在日志调试上,顺便推荐一下好用的BUG监控工具Fundebug原文:https://blog.bitsrc.io/a-comp...每周更新交流文章,微信搜索“大千世界”即可阅读提醒马上(比博客早一两篇)这篇文章在GitHub上https://github.com/qq449245884/xiaozhi已经收录了,整理了我的很多文档,欢迎star和完善。面试可以参考考点,另外关注公众号,后台就能看到福利了,你懂的。