我想在 Emscripten WebAssembly 运行期间显示进度条。但进度条会在 WebAssembly 完成后更新。有没有办法中断 WebAssembly(主线程)然后继续或强制 javascript(主线程)渲染 GUI?
main.js
Module.cwrap('calc', 'undefined', [])();
计算.cpp
void calc() {
EM_ASM({ progressBar($0); }, value); // here the progress bar should be updated immedately
...
calc something
...
}
// but it's updated only here
我也尝试过
progressbar(val) {
setTimeout(function(){ updateBar(val); }, 0);
}
不幸的是,对我来说,不可能在单独的文件中使用网络工作者。 谢谢...
不幸的是,无法强制 UI 渲染。我不知道是否可以打断 wasm,但这里有一个替代的想法。
考虑随着时间的推移分散计算,并给主线程(和事件循环)一些“呼吸空间”来更新 UI。
假设您正在计算总和,总共需要很多时间。您可以拆分计算,以便一次计算总和的一部分:
var sum = 0;
var i = setInterval(() => {
sum = calculatePartialSum(sum);
if(isDone(sum))
clearInterval(i); // stop
},0);
超时设置为 0 的 setInterval 将尽可能频繁地运行内部代码,但主线程(和 UI)可以在每次调用之间更新。
@schteppe:谢谢!对于有同样问题的人。我用 emscripten_async_call() 解决了它。
main.js
Module.cwrap('calc', 'undefined', [])();
计算.cpp
void calc() {
EM_ASM({ progressBar($0); }, value);
emscripten_async_call("calcfunction, NULL, msec");
}
void calcfunction() {
...
calc something
...
}
我用 SDL3 测试过的更完整的示例代码:
CMakeLists.txt
:target_link_options(${EXECUTABLE_NAME} PRIVATE
-sEXPORTED_RUNTIME_METHODS=["cwrap"])
target_link_options(${EXECUTABLE_NAME} PRIVATE
-sEXPORTED_FUNCTIONS=["_calc"])
index.js
:function progressBar(val) {
console.log(val);
}
Module["onRuntimeInitialized"] = function() {
const calc = Module.cwrap("calc", null, []);
calc();
};
main.cpp
:#include <emscripten.h>
void calcfunction(void *)
{
std::cout << "calc something" << std::endl;
}
extern "C"
{
void calc()
{
EM_ASM({ progressBar($0); }, 10);
emscripten_async_call(calcfunction, NULL, 0);
}
}
或使用这个:
extern "C"
{
void calc()
{
EM_ASM({ progressBar($0); }, 10);
emscripten_async_call(+[](void *){
std::cout << "calc something" << std::endl;
}, NULL, 0);
}
}