首页 > 其他分享 >WebAssembly入门笔记[4]:利用Global传递全局变量

WebAssembly入门笔记[4]:利用Global传递全局变量

时间:2024-01-30 09:03:13浏览次数:39  
标签:WebAssembly counter Global wasm externref 全局变量

利用WebAssembly的导入导出功能可以灵活地实现宿主JavaScript程序与加载的单个wasm模块之间的交互,那么如何在宿主程序与多个wasm之间传递和共享数据呢?这就需要使用到Global这个重要的对象了。

一、数值类型全局变量
二、将JavaScript函数设置为全局变量
三、利用全局变量处理字符串

一、数值类型全局变量

Global全局变量支持多种值类型,包括数组(i32/i64和f32/f64)、向量和引用类型(externref和funcref)。下面的实例利用Global提供了全局计数的功能。在WebAssembly Text Format (WAT)文件app.wat中,我们从宿主JavaScript应用中导入了一个i32类型的可读写(mut表示可以修改)的全局变量,导入路径为“imports.counter”,我们将其命名为$counter。在用于自增的导出函数increment中,我们通过执行global.get指令读取全局变量的值,并将其加1之后,执行global.set指令对全局变量重新赋值。

(module
   (global $counter (import "imports" "counter") (mut i32))
   (func (export "increment")
       (i32.add (global.get $counter) (i32.const 1))
       (global.set $counter)
   )
)

在index.html文件中,我们在页面中添加了一个“Increment”按钮,并利用一个<span>显式计算器当前的值。JavaScript脚本通过调用WebAssembly.Global构造函数将代表全局变量的Global对象创建出来后,调用WebAssembly.instantiateStreaming加载app.wat编译生成的app.wasm模块文件,并将此Global对象包含在导入对象中。

<html>
    <head></head>
    <body>
        <span id="counter">0</span>
        <button id="btnInc">Increment</button>
        <script>
            const globalCounter = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
            WebAssembly
                .instantiateStreaming(fetch("app.wasm"), {"imports":{"counter":globalCounter}})
                .then(results => {
                   document.getElementById("btnInc").onclick = ()=>{
                        results.instance.exports.increment();
                        document.getElementById("counter").innerText = globalCounter.value;
                   };
                });
        </script>
    </body>
</html>

wasm模块充成功导入后,我们注册了按钮的click事件,使之在调用导出的increment函数后,重新刷新计数器的值。如下图所示,针对“Increment”的每次点击都将计数器加1(源代码)。

image

二、将JavaScript函数设置为全局变量

除了四种数值类型,Global还支持两种引用类型externref和funcref,利用externref可以将宿主应用提供的任意JavaScript对象作为全局变量,下面的实例演示利用这种方式实现了与类似的功能。如下面的代码片段所示,新的app.wat导入了一个类型为externref的全局变量,对应着数组应用提供的一个用来对全局计数自增的Javascript函数。

(module
   (func $apply (import "imports" "apply") (param externref))
   (global $increment (import "imports" "increment") externref)
   (func $main
        (call $apply (global.get $increment))
   )
   (start $main)
)

由于JavaScript函数的引用在.wasm模块中并不能直接执行,所以我们不得不导入一个apply函数“回传”到宿主应用中执行。我们修改的应用用来统计导入的wasm模块的数量,所以我们在入口函数$main中利用apply调用了全局变量$increment引用的函数。

在index.html,我们在页面中添加了一个“Load”按钮来加载app.wat编译生成的app.wasm模块。JavaScript脚本利用counter变量表示加载的wasm模块数量,并通过调用WebAssembly.Global构造函数创建了rexternref类型的全局变量,其值为一个对counter自增的函数。

<html>
    <head></head>
    <body>
        <p>There are totally <span  id="counter" style= "color: read”>0</span> wasm modules loaded. </p>
        <button id="btnLoad">Load</button>
        <script>
            var counter = 0;
            const globalIncrement = new WebAssembly.Global({ value: "externref"}, ()=>counter++);
            var apply = func => func();
            document.getElementById("btnLoad").onclick = ()=>{
                WebAssembly
                    .instantiateStreaming(fetch("app.wasm"), {"imports":{"increment":globalIncrement,"apply": apply }})
                    .then(_=>{
                        document.getElementById("counter").innerText = counter;
                    })
                };
        </script>
    </body>
</html>

我们将这个Global对象包含到导入的对象中,并在导入成功后刷新显式的计数器,所以程序运行后将会显式当前加载的wasm模块数量(源代码)。

image

三、利用全局变量处理字符串

WebAssembly目前并没有提供针对字符串类型的直接支持,而是单纯地将其作为字节序列看到。目前字符串在宿主程序与wasm模块之间的传递只有通过Memory来实现。由于Javascript具有处理字符串的能力,wasm模块可以将字符串作为externref回传到宿主程序进行处理。在接下来演示的程序中,我们在app.wat中定义一个“字符类型(实际上是externref类型)”的全局变量,导出的greet函数通过调用导入的print函数将其输出。

(module
   (func $print (import "imports" "print") (param externref))
   (global $message (import "imports" "message") (mut externref))
   (func (export "greet")
        (call $print (global.get $message))
   )
)

在index.html中,我们在页面上放置了三个按钮,让它们在命名为“greet”的<div>中分别显示“Good Morning”、“Good Afternoon”和“Good Evening”三条问候语。具体的问候语通过函数print输出,它的参数就是代表输出文本的字符串。

<html>
    <head></head>
    <body>
        <div id="greet"></div>
        <button id="btnMorning">Morning</button>
        <button id="btnAfternoon">Afternoon</button>
        <button id="btnEvening">Evening</button>
        <script>
            var print = (msg) => {
                console.log(msg);
                document.getElementById("greet").innerText = msg;
            }
            const globalMsg = new WebAssembly.Global({ value: "externref", mutable: true }, "Good Morning!");
            console.log(globalMsg.value);
            WebAssembly
                .instantiateStreaming(fetch("app.wasm"), {"imports":{"message":globalMsg, "print":print}})
                .then(results => {
                    var greet = results.instance.exports.greet;
                    console.log(greet);
                    document.getElementById("btnMorning").onclick = ()=>{
                        globalMsg.value = "Good Morning!";
                        greet();
                    };
                    document.getElementById("btnAfternoon").onclick = ()=>{
                        globalMsg.value = "Good Afternoon!";
                        greet();
                    };
                    document.getElementById("btnEvening").onclick = ()=>{
                        globalMsg.value = "Good Evening!";
                        greet();
                    };
                });
        </script>
    </body>
</html>

我们定义了一个externref类型的Global对象来引用带输出的问候语文本,并在加载app.wasm木块使将其包含到导入对象中。三个按钮的click事件处理程序通过调用导出的greet函数输出对于的问候语,但是在调用此函数之前会对Global对象进行相应的赋值(源代码)。

image

WebAssembly入门笔记[1]:与JavaScript的交互
WebAssembly入门笔记[2]:利用Memory传递字节数据
WebAssembly入门笔记[3]:利用Table传递引用
WebAssembly入门笔记[4]:利用Global传递全局变量

标签:WebAssembly,counter,Global,wasm,externref,全局变量
From: https://www.cnblogs.com/artech/p/17982720/hello_wasm_4

相关文章

  • AlipayGlobal集成备忘录
    一、获取clientId,publicKey,privateKey登录开发者中心https://global.alipay.com/developer如果当前账号尚未配置publicKey,则需要你下载阿里官方提供的工具去生成一个最终你要使用的publicKey和privateKey分别来自以下两个地方另外开发者中心提供如图所示工具,进行一系......
  • WebAssembly入门笔记[3]:利用Table传递引用
    在《WebAssembly入门笔记[2]》中,我们介绍了如何利用Memory在作为宿主的JavaScript应用和wasm模块之间传递数据,但是Memory面向单纯二进制字节的读写在使用起来还是不太方便,此时我们会更多地用到另一个重要的对象Table。Table利用用来存储一组指定类型的对象,说得准确一点是对象的引......
  • WebAssembly入门笔记[2]:利用Memory传递数据
    利用灵活的“导入”和“导出”机制,WebAssembly与承载的JavaScript应用之间可以很便利地“互通有无”。《与JavaScript的交互》着重演示了如何利用函数的导入和导出实现功能的共享,接下来我们主要关注数据的传递或者共享。宗地来说,WebAssembly与宿主程序之间的数据传递主要有如下三......
  • rust使用lazy_static对全局变量多线程并发读写示例
    首先需要在项目依赖Cargo.toml添加lazy_static依赖项[dependencies]lazy_static="1.4.0"示例代码如下:uselazy_static::lazy_static;usestd::sync::{RwLock,RwLockReadGuard,RwLockWriteGuard};usestd::thread;#[derive(Debug)]structSharedData{data:Vec<......
  • C++ const 全局变量跨文件引用,无法解析的外部符号?
    前两天群里有人问了这样一个问题:在a文件中定义了一个全局变量,可以在b文件中引用。但一旦把全局变量改为const之后,就无法在b文件中引用,编译(链接)报错“无法解析的外部符号”,这是为什么?这是因为const修饰的变量默认具有文件作用域,如果想和非const变量一样具有全局作......
  • JavaScript保留字和预定义的全局变量及函数汇总
    保留字也称关键字,每种语言中都有该语言本身规定的一些关键字,这些关键字都是该语言的语法实现基础,JavaScript中规定了一些标识符作为现行版本的关键字或者将来版本中可能会用到的关键字,所以当我们定义标识符时就不能使用这些关键字了,下面介绍下JavaScript保留字和预定义的全局变量......
  • jenkins启动报错:Failed Loading global config
    jenkins启动报错:FailedLoadingglobalconfig 问题起因:想在构建项目中使用复选框(ExtendedChoiceParameter),需要安装ExtendedChoiceParameter插件,但是因为版本过低的原因,导致插件无法正常安装。然后根据提示,就在jenkins的web页面进行了自动升级。但是在升级过程中......
  • Inserting a node at beginning,全局变量头指针【1月16日学习笔记】
    点击查看代码//insertinganodeatbeginning,全局变量头指针#include<iostream>usingnamespacestd;structnode{ intdata; node*next;};node*A;voidinsert(intx){ node*temp=newnode;//创建新节点 temp->data=x; temp->next=A;//新节点尾巴指......
  • GlobalProtect 证书连接问题
    故障现象使用GlobalProtect时,软件提示ConnectionFailed,Gateway证书验证失败。排错方法打开GlobalProtect的Settings在Troubleshooting中选择CollectLogs,之后系统会将日志打包保存到本地。 解压后需要PanGPA.log这个日志文件,在日志文件中看到和UI一致的日志,证书验......
  • 【C语言】全局变量与局部变量
    在不同的函数之间传递数据时,可以使用如下方法:参数:通过形参和实参返回值:用return语句返回计算结果全局变量全局变量与局部变量全局变量:函数之外定义的变量称为全局变量(外部变量);局部变量:在一个函数内部定义的变量称为局部变量(内部变量)。全局变量使用:#include<stdio.h......