如何通过Emscripten/embind在C++中以await方式调用JS异步函数
在Emscripten 1.38.31中实现JS异步函数的"await"式调用
由于Emscripten运行在浏览器主线程(或Worker)环境中,无法直接实现类似JS的同步await(会阻塞事件循环导致页面无响应),但可以通过Promise回调绑定的方式模拟异步等待效果,以下是具体实现方案:
核心思路
JS的async函数本质返回Promise,我们可以在C中调用该函数后,给返回的Promise绑定then回调,当Promise resolve时触发C的处理逻辑。
方案一:直接绑定Promise回调
#include <emscripten.h> #include <emscripten/val.h> #include <string> using namespace emscripten; emscripten::val func2; // 处理JS异步函数返回结果的C++回调 void handle_get_data_result(emscripten::val result) { std::string data = result.as<std::string>(); // 此处编写拿到数据后的业务逻辑 printf("JS异步函数返回数据:%s\n", data.c_str()); } void set_js_func(emscripten::val func) { func2 = func; // 调用JS异步函数,并为返回的Promise绑定then回调 func2().call<void>("then", emscripten::val::module_property("handle_get_data_result")); } // 绑定C++函数到JS环境 EMSCRIPTEN_BINDINGS(my_module) { emscripten::function("setJSFunction", &set_js_func); emscripten::function("handle_get_data_result", &handle_get_data_result); }
方案二:封装异步调用逻辑(贴近await使用体验)
如果需要多次调用异步函数并在拿到结果后执行后续逻辑,可以封装一个异步调用函数,通过回调传递结果:
#include <emscripten.h> #include <emscripten/val.h> #include <string> #include <functional> using namespace emscripten; emscripten::val func2; std::function<void(std::string)> pending_callback; void handle_get_data_result(emscripten::val result) { std::string data = result.as<std::string>(); if (pending_callback) { // 触发回调,传递异步结果 pending_callback(data); pending_callback = nullptr; } } // 封装的"await"式调用函数 void await_get_data(std::function<void(std::string)> callback) { if (func2.isUndefined()) { printf("未设置JS异步函数\n"); return; } pending_callback = callback; func2().call<void>("then", emscripten::val::module_property("handle_get_data_result")); } // 示例:调用封装函数 void demo_usage() { await_get_data([](std::string data) { printf("获取到异步数据:%s\n", data.c_str()); // 此处编写原本要在"await"之后执行的逻辑 }); } EMSCRIPTEN_BINDINGS(my_module) { emscripten::function("setJSFunction", &set_js_func); emscripten::function("handle_get_data_result", &handle_get_data_result); emscripten::function("demoUsage", &demo_usage); // 可选:暴露给JS调用示例 }
关键注意事项
- 禁止同步阻塞:不要尝试在C++中同步等待Promise结果,这会卡死浏览器主线程,所有异步逻辑必须基于回调实现。
- 函数绑定要求:用于处理结果的C++回调必须通过
EMSCRIPTEN_BINDINGS暴露给JS环境,否则无法被Promise的then方法调用。 - 版本兼容性:该方案完全适配Emscripten 1.38.31,无需依赖高版本特性。
内容的提问来源于stack exchange,提问作者user558185
相关产品推荐
相关产品推荐

