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

Qt6.8.2中JavaScript调用WebAssembly的js文件<2>

上一篇文章介绍了javaScript如何调用简单的加法运算,该js的编译是采用cmd指令进行的,今天我为大家介绍如何使用QtCreator的WebAssembly套件编译成js、wasm,并且让javascript进行调用。

那么还是以简单的加法运行为例。

功能介绍

开发环境:win11 + Qt 6.8.2

1:创建一个简单项目

打开QtCreator开发工具,选择一个模块,按照下面的步骤进行操作

 

 2:添加导出函数

因为只是导出一个简单的加法函数,直接在"main.cpp"中添加就可以了。

程序创建后未曾修改过的的"main.cpp"

 添加"add"导出函数

#include <emscripten.h>
extern "C" EMSCRIPTEN_KEEPALIVE int add(int a, int b) 
{
    return a + b;
}

代码解析:将 add 函数以 C 语言的链接方式导出到 WebAssembly 模块中,并确保其不被编译器删除。

使用场景:当需要通过 JavaScript 调用 C++ 函数时(例如在 Qt Creator 编译的 WebAssembly 项目中),此代码为函数提供了跨语言调用的桥梁。

此时没有涉及到页面操作,所以去除了main函数里面的内容,对mian函数的修改,如下:

int main()
{
    return 0;
} // 必须保留main函数

踩坑:在这里必须要保留main函数,否则生成的js胶水代码被html调用时在浏览器中会有callMain未定义的错误!!!

完整的main.cpp的代码,如下:

#include <emscripten.h>

extern "C" EMSCRIPTEN_KEEPALIVE int add(int a, int b) {
    return a + b;
}

int main()
{
    return 0;
} // 必须保留main函数

3:修改pro配置信息

原始未修改的pro文件,如下所示:

 1:去除widget文件的调用

2:添加生成目录

为了方便查找到生成的js文件,可以添加生成目录

 好了到这里对代码的修改就已经完成了,对项目进行清除、构建。程序应该是不会出问题的,如果有问题,请私信我哟~咱们一块解决!

编译完成后,就可以看到bin文件夹下面的内容了。

 4:html调用胶水代码

在bin目录下创建一个xx.html文件,用来调用SingleThreadDemo.js文件。

假设调用胶水代码的html名称是:demo1.html

步骤一

调用SingleThreadDemo.js文件

<script type="text/javascript" src="SingleThreadDemo.js"></script>

先加载文件,加载完成后再进行操作,等待js文件加载完以后再做处理。

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>调用 SingleThreadDemo</title>
    <script type="text/javascript" src="SingleThreadDemo.js"></script>
</head>
<body>
    <script>
        document.addEventListener('DOMContentLoaded', async () => {
            try {
				console.log('SingleThreadDemo.js已定义!加载完成!');
            } catch (error) {
                console.error('模块初始化或调用函数时出错:', error);
            }
        });
    </script>
</body>
</html>

步骤二

在bin文件夹下打开cmd命令行,启动python服务

python -m http.server

 步骤三

使用谷歌浏览器打开demo1.html查看控制台信息,SingleThreadDemo.js胶水代码是否加载成功。

输入地址:http://localhost:8000/demo1.html

 发现控制台有一个404的错误

 在谷歌浏览器中也同样有错误输出

 解决方法:

因为在bin文件夹中没有找到favicon.ico图片资源,导致有问题。该图片其实是Qt的图标,只需要从电脑中搜索到该图片后,拷贝到bin文件中,就不会出现这个问题了。

 此时,再一次在浏览器中打开"localhost:8000/demo1.html"地址,就不会再报错了。

 使用document.addEventListener监听整个文档,事件触发时,执行传入的回调函数,使用try/catch方法捕获异步操作中的错误,比如:文件加载失败、函数调用异常等等,方便我们排查错误。

步骤四

调用SingleThreadDemo.js胶水代码。这也是调用的最核心部分了!

首先,打开SingleThreadDemo.js胶水代码,发现虽然只导出了一个加法函数,但是js居然有一万多行代码,很是震惊呀!

直接将代码拉到最底端,会有一个导出方法,如下:

if (typeof exports === 'object' && typeof module === 'object')
  module.exports = SingleThreadDemo_entry;
else if (typeof define === 'function' && define['amd'])
  define([], () => SingleThreadDemo_entry);

这句代码时一个典型的UMD(Universal Module Definition)模式,让 SingleThreadDemo_entry 模块在不同的 JavaScript 环境中(如 CommonJS、AMD 或全局变量)都能被正确导出。

由此得出,在demo.html中使用胶水代码时,导出的模块是:SingleThreadDemo_entry。

我在看其他博友给出的例子中,很多都是使用Module的调用,比如:

 刚开始调用的时候,我也是拿着"Module"来操作,但是浏览器控制台一直输出,Module找不到,于是我就顺着这个思路开始解决,走了好几天弯路,我才明白,别人使用Module能成功是因为导出的名称叫Module,而我导出的胶水代码中时SingleThreadDemo_entry

 既然知道该如何正确使用导出模块后,那就尝试使用加法函数吧!

步骤五

在demo1.html中输出SingleThreadDemo_entry是什么类型?

console.log('类型是:',typeof SingleThreadDemo_entry());

经过运行后发现,此时SingleThreadDemo_entry()是一个object,那么该如何访问它里面的函数呢?

SingleThreadDemo_entry().then(function(module){
    console.log('SingleThreadDemo_entry().then(function(module)');
	var result = module._add(7,4);
	console.log("5 + 3 =", result); // 应该输出 8
});

代码解析分析:

1:SingleThreadDemo_entry()

调用模块入口函数,返回Promise,因为加载模块是一个异步操作,使用Promise可以很好的处理这个过程。

该函数有三个返回状态

  • pending(进行中):初始状态,表示异步操作还在进行中。
  • fulfilled(已成功):表示异步操作已经成功完成。
  • rejected(已失败):表示异步操作失败。

2:.then()方法

.then()是Promise对象的方法,用于注册回调函数。它接受两个可选参数:

  • 第一个参数:是一个回调函数,当 Promise 对象的状态变为 fulfilled 时,这个回调函数会被执行。
  • 第二个参数:也是一个回调函数,当 Promise 对象的状态变为 rejected 时,这个回调函数会被执行。不过在 SingleThreadDemo_entry().then(function(module) { ... }) 中,只提供了第一个参数。

3:function(module) {...}

回调函数,这是传递给.then()方法的回调函数,当SingleThreadDemo_entry返回的Promise对象编程fulfilled时,这个回调函数会被调用。

参数modulePromise解决的值,通常在加载WebAssembly模块的场景中,module可能是加载完成的WebAssembly模块实例,通过这个实例可以调用模块导出的函数。

完整的html代码,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>调用 SingleThreadDemo</title>
    <script type="text/javascript" src="SingleThreadDemo.js"></script>
</head>
<body>
    <script>
        document.addEventListener('DOMContentLoaded', async () => {
            try {
				console.log('SingleThreadDemo.js已定义!加载完成!');
				if(typeof SingleThreadDemo_entry === 'undefined')
				{	
					console.error('SingleThread2_entry未定义,请检查胶水代码');
					return;
				}
				console.log('类型是:',typeof SingleThreadDemo_entry());
				SingleThreadDemo_entry().then(function(module){
					console.log('SingleThreadDemo_entry().then(function(module)');
					var result = module._add(7,4);
					console.log("7 + 4 =", result); 
				});
            } catch (error) {
                console.error('模块初始化或调用函数时出错:', error);
            }
        });
    </script>
</body>
</html>

还有另一种调用方式,也可以成功

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>调用 SingleThreadDemo</title>
    <script type="text/javascript" src="SingleThreadDemo.js"></script>
</head>
<body>
    <script>
		console.log('typeof SingleThreadDemo_entry = ', typeof SingleThreadDemo_entry);
		SingleThreadDemo_entry().then((instance) => {
			console.log('现在 instance 是你需要的实例对象');
			var resultAdd = instance._add(5, 6);
			console.log('result = ', resultAdd);
        }).catch((error) => {
            console.error('加载 WebAssembly 模块时出错:', error);
        });
    </script>
</body>
</html>

好了,重新启动下"http://localhost:8000/demo1.html"就能看到输出结果了!

简单的使用QtCreator的WebAssembly编译的加法导出函数已经讲解完了,希望对一些初学者有帮助哟!

我是糯诺诺米团,一名C++程序媛~

相关文章:

  • Redis JSON 用id读取content总结(sendCommand())
  • VLLM专题(二十一)—分布式推理与服务
  • Unity URPShader:实现和PS一样的色相/饱和度调整参数效果
  • MarsCode AI实战:利用DeepSeek 快速搭建你的口语学习搭子
  • HttpClient通讯时间过久
  • 计算机网络技术服务管理基于Spring Boot-SSM
  • 前端流式输出实现详解:从原理到实践
  • 模型部署实战:PyTorch生产化指南
  • git clone项目报错fatal: fetch-pack: invalid index-pack output问题
  • 红日靶场(二)——个人笔记
  • TCP心跳消息
  • Multisim学习-01 特点安装使用和第一个仿真实例
  • 计算机组成原理 第六章 总线
  • 图像分割的mask有空洞怎么修补
  • tldr命令助记
  • Qt 控件概述 QLCDNumber 和 Progressbar
  • 手动集成sqlite的方法
  • 我开发的PDF转WORD免费工具
  • 【LangChain入门 4 Prompts组件】提示词追加示例 FewShotPromptTemplate和示例选择器ExampleSelector
  • Vision-R1:用 “冷启动 + 强化学习” 解锁多模态模型的推理能力
  • 中方发布会:中美经贸高层会谈取得了实质性进展,达成了重要共识
  • 中美经贸高层会谈11日在日内瓦将继续进行
  • 印巴战火LIVE丨“快速接近战争状态”:印度袭击巴军事基地,巴启动反制军事行动
  • 2025年4月份CPI环比由降转涨,核心CPI涨幅稳定
  • 优秀“博主”在上海杨浦购房最高补贴200万元,有何条件?
  • 王受文已任全国工商联党组成员