当前位置: 首页 > news >正文

微信小程序调用 WebAssembly 烹饪指南

我们都是在夜里崩溃过的俗人,所幸终会天亮。明天就是新的开始,我们会变得与昨天不同。

一、Rust 导出 wasm

参考 wasm-bindgen 官方指南 https://wasm.rust-lang.net.cn/wasm-bindgen/introduction.html

wasm-bindgen,这是一个 Rust 库和 CLI 工具,它可以促进 wasm 模块和 JavaScript 之间的高级交互。

1、创建一个 wasm 项目

# 使用模板生成
# cargo generate --git https://gitee.com/tgodfather/wasm-pack-template
cargo generate --git https://github.com/rustwasm/wasm-pack-template

2、添加 js-sys 依赖

cargo add js-sys 

3、修改 lib.rs

定义三个外部函数,它们分别对应于 JavaScript 中的 console.logconsole.error 和 wx.showModal。通过使用 wasm_bindgen,这些函数可以在 Rust 代码中被调用,从而实现与 JavaScript 的交互。

#[wasm_bindgen]
extern "C" {#[wasm_bindgen(js_namespace = console)]fn log(s: &str);#[wasm_bindgen(js_namespace = console)]fn error(s: &str);#[wasm_bindgen(js_namespace = wx)]fn showModal(param: &Object);
}

使用 rust 分别调用这三个函数,导出为 wasm 函数,

#[wasm_bindgen]
pub fn rs_log() {log("log");
}#[wasm_bindgen]
pub fn rs_error() {log("error");
}#[wasm_bindgen]
pub fn rs_show_modal() {// 创建一个 JavaScript 对象let options = Object::new();// 设置对象的属性Reflect::set(&options,&JsValue::from_str("title"),&JsValue::from_str("提示"),).unwrap();Reflect::set(&options,&JsValue::from_str("content"),&JsValue::from_str("这是一个模态弹窗"),).unwrap();// 创建回调函数let success_callback = Closure::wrap(Box::new(|res: JsValue| {let confirm = Reflect::get(&res, &JsValue::from_str("confirm")).unwrap().as_bool().unwrap_or(false);let cancel = Reflect::get(&res, &JsValue::from_str("cancel")).unwrap().as_bool().unwrap_or(false);if confirm {log("用户点击确定");} else if cancel {log("用户点击取消");}}) as Box<dyn FnMut(_)>);// 将回调函数添加到对象中Reflect::set(&options,&JsValue::from_str("success"),success_callback.as_ref().unchecked_ref(),).unwrap();// 为了避免回调被回收,必须调用 `forget`success_callback.forget();// 调用 JavaScript 的 `showModal` 函数showModal(&options);
}

补充:小程序官方弹窗示例代码,

wx.showModal({title: '提示',content: '这是一个模态弹窗',success (res) {if (res.confirm) {console.log('用户点击确定')} else if (res.cancel) {console.log('用户点击取消')}}
})

4、编译打包 wasm

wasm-pack build --target web

可以看到在 pkg 目录下生成了我们需要用到的 mywasm_bg.wasm、mywasm.js 。

二、对应小程序相关改动(Rust)

对于微信小程序,直接编译打包后的包无法直接调用,所以还需要进行一些代码修改。

WXWebAssembly | 微信开放文档

1、新增目录

新增 workers 目录:与 pages 同级,创建 workers 目录,用于存放 .wasm 文件

workers 目录只存放 mywasm_bg.wasm,便于把.wasm打包进去,以及分包打包

新增 pages/worker 目录:用于进行打包文件的调用

pages/worker目录只存放 .js ,这个文件包含了一些调用 .wasm 文件的方法

2、修改 mywasm.js 胶水代码

#改动点1、注释原 __wbg_load 方法逻辑,替换使用以下代码async function __wbg_load(module, imports) {if (typeof Response === 'function' && module instanceof Response) {const bytes = await module.arrayBuffer();return await instantiateArrayBuffer(bytes, imports);} else {return await instantiateArrayBuffer(module, imports);}
}
# 改动点2、手动指定 WebAssembly 模块的路径// 手动指定 WebAssembly 模块的路径
const wasmModulePath = '/workers/mywasm_bg.wasm';async function instantiateArrayBuffer(binaryFile, imports) {return WXWebAssembly.instantiate(wasmModulePath, imports).then(function(instance) {return instance;}).catch(function(reason) {console.error('Failed to asynchronously prepare wasm: ' + reason);throw reason;});
}
# 改动点3、手动指定 WebAssembly 模块的路径if (typeof module_or_path === 'undefined') {// module_or_path = new URL('mywasm_bg.wasm',//   import.meta.url);module_or_path =  wasmModulePath;}if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {// 需要使用 wx.request 替代 fetch      // module_or_path = fetch(module_or_path);module_or_path =  wasmModulePath;}

3、调用 wasm

import init,{ rs_log ,rs_error,rs_show_modal}  from '../worker/mywasm.js';
  onLoad: async function () {try {await init();// 使用 wasmModule 中的导出函数rs_log();rs_error();rs_show_modal();} catch (e) {console.error('Failed to load WASM module:', e);}}

4、运行效果

从控制台日志输出可以看到,wasm 导出的函数运行成功。

三、C/C++  导出 wasm

1、创建一个 hellojs.cpp

#include <stdio.h>
#include <emscripten/emscripten.h>int main(int argc, char ** argv) {printf("Hello World\n");
}#ifdef __cplusplus
extern "C" {
#endifint EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) {printf("我的函数已被调用\n");
}#ifdef __cplusplus
}
#endif

2、使用 emcc 编译打包

 # emcc -o hellojs.html hellojs.cpp -O3 -s WASM=1 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" --shell-file html_template/shell_minimal.htmlemcc -o hellojs.html hellojs.cpp -O3 -s WASM=1 -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']" --shell-file html_template/shell_minimal.html

成功生成我们所需要的 hellojs.js、hellojs.wasm 文件。 

四、对应小程序相关改动(C++)

1、新增目录

新增 workers 目录:与 pages 同级,创建 workers 目录,用于存放 .wasm 文件

workers 目录只存放 mywasm_bg.wasm,便于把.wasm打包进去,以及分包打包

新增 pages/worker 目录:用于进行打包文件的调用

pages/worker目录只存放 .js ,这个文件包含了一些调用 .wasm 文件的方法

2、修改 hellojs.js 胶水代码

# 改动1、在文件的最底部添加
module.exports = {Module: Module
}
# 改动2、注释代码
if(ENVIRONMENT_IS_WORKER) {// scriptDirectory=self.location.href}
# 改动3、修改instantiateArrayBuffer函数// function instantiateArrayBuffer(binaryFile, imports, receiver) {
//     return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary, imports)).then(receiver, reason=> {
//             err(`failed to asynchronously prepare wasm: ${reason}`); abort(reason)
//         })
// }
function instantiateArrayBuffer(binaryFile, imports, receiver) {return WXWebAssembly.instantiate('/workers/hellojs.wasm', imports).then(function(instance) {return instance;}).then(receiver, function(reason) {err('failed to asynchronously prepare wasm: ' + reason);// Warn on some common problems.if (isFileURI(wasmBinaryFile)) {err('warning: Loading from a file URI (' + wasmBinaryFile + ') is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing');}abort(reason);})
}
# 改动4、将js文件中的所有WebAssembly修改为WXWebAssemblyfunction abort(what) {Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";//var e=new WebAssembly.RuntimeError(what);var e=new WXWebAssembly.RuntimeError(what);throw e
}function instantiateAsync(binary, binaryFile, imports, callback) {if( !binary&&typeof WXWebAssembly.instantiateStreaming=="function" && !isDataURI(binaryFile)&& !isFileURI(binaryFile)&& !ENVIRONMENT_IS_NODE&&typeof fetch=="function") {return fetch(binaryFile, {credentials:"same-origin"}).then(response=> {var result=WXWebAssembly.instantiateStreaming(response, imports); return result.then(callback, function(reason) {err(`wasm streaming compile failed: ${reason}`); err("falling back to ArrayBuffer instantiation"); return instantiateArrayBuffer(binaryFile, imports, callback)})})
}return instantiateArrayBuffer(binaryFile, imports, callback)
}

3、调用 wasm

# 引入文件
const hellojs_wasm = require('../worker/hellojs');
onReady() {const moudule = hellojs_wasm.Module// moudule._myFunction(1,"");moudule.ccall("myFunction", // name of C functionnull, // return typenull, // argument typesnull,); // arguments},

4、运行效果

从控制台日志输出可以看到,wasm 导出的函数运行成功。 

五、参考资料

基于 Rust 的 Wasm 开发探索与实践_rust wasm-CSDN博客

基于 Rust 的 Wasm/Wasi 开发探索与实践(Linux开发环境)_wasi安装-CSDN博客

基于 Emscripten + OpenXLSX 实现浏览器操作 Excel_使用webassembly在浏览器端操作excel-CSDN博客

相关文章:

微信小程序调用 WebAssembly 烹饪指南

我们都是在夜里崩溃过的俗人&#xff0c;所幸终会天亮。明天就是新的开始&#xff0c;我们会变得与昨天不同。 一、Rust 导出 wasm 参考 wasm-bindgen 官方指南 https://wasm.rust-lang.net.cn/wasm-bindgen/introduction.html wasm-bindgen&#xff0c;这是一个 Rust 库和 CLI…...

# LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game)

LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game) 在本篇博客中&#xff0c;我们将深入探讨 LeetCode 第2038题——如果相邻两个颜色均相同则删除当前颜色。该问题涉及字符串处理与游戏策略&#xff0c;旨在考察如何在给定规则下判断游戏的…...

Redis面试相关

Redis开篇 使用场景 缓存 缓存穿透 解决方法一&#xff1a; 方法二&#xff1a; 通过多次hash来获取对应的值。 小结 缓存击穿 缓存雪崩 打油诗 双写一致性 两种不同的要求 强一致 读锁代码 写锁代码 强一致&#xff0c;性能低。 延迟一致 方案一&#xff1a;消息队列 方…...

4.CSS文本属性

4.1文本颜色 div { color:red; } 属性值预定义的颜色值red、green、blue、pink十六进制#FF0000,#FF6600,#29D794RGB代码rgb(255,0,0)或rgb(100%,0%,0%) 4.2对齐文本 text-align 属性用于设置元素内文本内容的水平对齐方式。 div{ text-align:center; } 属性值解释left左对齐ri…...

Mongo高可用架构解决方案

Mongo主从复制哪些事(仅适用特定场景) 对数据强一致性要求不高的场景,一般微服务架构中不推荐 master节点可读可写操作,当数据有修改时,会将Oplog(操作日志)同步到所有的slave节点上。那么对于从节点来说仅只读,所有slave节点从master节点同步数据,然而从节点之间互相…...

Rabbitmq 业务异常与未手动确认场景及解决方案

消费端消费异常&#xff0c;业务异常 与 未手动确认是不是一个场景&#xff0c;因为执行完业务逻辑&#xff0c;再确认。解决方案就一个&#xff0c;就是重试一定次数&#xff0c;然后加入死信队列。还有就是消费重新放入队列&#xff0c;然后重新投递给其他消费者&#xff0c;…...

linux,centos7.6安装禅道

1.cd /opt 2.wget https://www.zentao.net/dl/zentao/18.5/ZenTaoPMS.18.5.zbox_64.tar.gz 3.tar xvzf ZenTaoPMS.18.5.zbox_64.tar.gz 4./opt/zbox/zbox --aport 4005 --mport 3307 start 安全组开启一下两个端口 –aport 4005&#xff1a;设置Apache启动端口为4005 –mport 3…...

java基础之代理

代理模式&#xff08;Proxy Pattern&#xff09; 简介 是一种结构型设计模式&#xff0c;主要用于为某对象提供一个代理对象&#xff0c;以控制对该对象的访问。通过引入一个代理对象来控制对原对象的访问。代理对象在客户端和目标对象之间充当中介&#xff0c;负责将客户端的…...

计算机网络——期末复习(6)期末考试样例2(含答案)

一、单项选择题(每题1分&#xff0c;共10小题&#xff0c;共计10分) 1.因特网多播采用的管理协议是( )协议。 A.UDP B.BGP C.IGMP D.TCP 2.采用CIDR时&#xff0c;某计算机的IP地址是202.35.79.88/19&#xff0c;该计算机所处子网的地址是( )。 A.202.35.0.…...

JavaScript 获取DOM对象

html的标签被js获取到之后就变成了js对象&#xff0c;对象里面包含了标签的属性和方法 。同一时间获取多个对象则会翻译一个数组&#xff0c;数组元素是对象 获取方法 1. const a document.getElementById("id")&#xff0c;根据标签的id来获取。因为id是唯一的、…...

一文讲明白朴素贝叶斯算法及其计算公式(入门普及)

1、贝叶斯算法 贝叶斯定理由英国数学家托马斯贝叶斯 ( Thomas Bayes) 提出的&#xff0c;用来描述两个条件概率之间的关系。通常&#xff0c;事件A在事件B 发生的条件下与事件 B 在事件 A 发生的条件下&#xff0c;它们两者的概率并不相同&#xff0c;但是它们两者之间存在一定…...

实际开发中,常见pdf|word|excel等文件的预览和下载

实际开发中,常见pdf|word|excel等文件的预览和下载 背景相关类型数据之间的转换1、File转Blob2、File转ArrayBuffer3、Blob转ArrayBuffer4、Blob转File5、ArrayBuffer转Blob6、ArrayBuffer转File 根据Blob/File类型生成可预览的Base64地址基于Blob类型的各种文件的下载各种类型…...

Python自学 - 递归函数

1 Python自学 - 递归函数 递归函数是一种在函数体内调用自己的函数&#xff0c;就像“左脚踩着右脚&#xff0c;再右脚踩着左脚… 嗯&#xff0c;你就可以上天了&#xff01;”。递归函数虽然不能上天&#xff0c;但在处理某些场景时非常好用&#xff0c; 一种典型的场景就是遍…...

Spark-Streaming有状态计算

一、上下文 《Spark-Streaming初识》中的NetworkWordCount示例只能统计每个微批下的单词的数量&#xff0c;那么如何才能统计从开始加载数据到当下的所有数量呢&#xff1f;下面我们就来通过官方例子学习下Spark-Streaming有状态计算。 二、官方例子 所属包&#xff1a;org.…...

Markdown如何导出Html文件Markdown文件

Markdown如何导出Html文件Markdown文件 前言语法详解小结其他文章快来试试吧☺️ Markdown 导出 HTML &#x1f448;点击这里也可查看 前言 Markdown的源文件以md为后缀。Markdown是HTML语法的简化版本&#xff0c;它本身不带有任何样式信息。我们所看到的Markdown网页(如&…...

使用Python进行图像裁剪和直方图分析

一、简介 在数字图像处理领域&#xff0c;裁剪和分析图像的直方图是两个非常基本且重要的操作。本文将通过一个简单的Python项目&#xff0c;展示如何使用skimage和matplotlib库来裁剪图像并分析其RGB通道的直方图。 二、环境准备 在开始之前&#xff0c;请确保你已经安装了以…...

企业内管信息化系统

本文结尾处获取源码。 本文结尾处获取源码。 本文结尾处获取源码。 一、相关技术 后端&#xff1a;Java、JavaWeb / Springboot。前端&#xff1a;Vue、HTML / CSS / Javascript 等。数据库&#xff1a;MySQL 二、相关软件&#xff08;列出的软件其一均可运行&#xff09; I…...

【python因果库实战15】因果生存分析4

这里写目录标题 加权标准化生存分析总结个体层面的生存曲线 加权标准化生存分析 我们还可以将加权与标准化结合起来&#xff0c;使用 WeightedStandardizedSurvival 模块。在这里&#xff0c;我们将逆倾向得分加权模型&#xff08;根据基线协变量重新加权人群&#xff09;与加…...

Linux 线程详解

目录 一、线程概述 二、线程创建 三、线程终止 四、线程回收 五、线程取消 六、线程分离 七、线程安全 一、线程概述 线程是进程内的一个执行单元&#xff0c;是进程内可调度的实体。一个进程可以包含多个线程&#xff0c;这些线程共享进程的资源&#xff0c;如内存空…...

云架构:考量与框架

云架构&#xff1a;考量与框架 引言 在当今的数字化环境中&#xff0c;云计算已成为现代商业运营的基石。一个设计良好的云架构框架为可扩展、安全和弹性的系统奠定了基础。本文将深入探讨云架构的核心要素&#xff0c;讨论重要的考量因素、设计指南&#xff0c;以及最佳实践…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...