WASM 调用 js 代码
Emscripten 提供了两种方式,用于从 C/C++ 调用 JavaScript 的方法:
- 使用
emscripten_run_script()
运行脚本 - 编写
inline JavaScript
。
-
最直接但稍微慢的方式是使用
emscripten_run_script()
。这有效地使用eval()
在 C/C++ 中运行指定的 JavaScript 代码。例如,调用浏览器的alert()
函数,例如下面的代码:int EMSCRIPTEN_KEEPALIVE runScript(){ emscripten_run_script("alert('hi')"); emscripten_run_script("console.log('hello world!')"); return 0; }
-
从 C 中调用 JavaScript 接口的一种更快的方法是编写
inline JavaScript
,使用EM_JS()
或EM_ASM()
(以及其它相关的宏)。-
EM_JS
是在 C 文件中声明一个 JavaScript 函数,使用方法参考这里。#include <emscripten.h> EM_JS(void, myAlert, (), { alert('hello world!'); throw 'all done'; // exception }); EM_JS(void, take_args, (int x, float y), { console.log('I received: ' + [x, y]); }); EM_JS(void, say_hello, (const char* cstr), { console.log('Hello, ', UTF8ToString(cstr)); }); EM_JS(int, add_forty_two, (int n), { return n + 42; }); EM_JS(int, get_memory_size, (), { return HEAP8.length; }); int main() { myAlert(); take_args(10, 20.4f); say_hello("C++"); int x = add_forty_two(100); int y = get_memory_size(); cout << "return value of add_forty_two is " << x << endl; cout << "HEAP8 memory size is " << y << endl; return 0; }
-
EM_ASM
的使用方式与inline assembly
代码类似#include <emscripten.h> int main() { EM_ASM( alert('hello world!'); throw 'all done'; ); // pass params from C to javascript EM_ASM({ console.log('I received: ' + $0); }, 100); // return value back int x = EM_ASM_INT({ console.log('I received: ' + $0); return $0 + 1; }, 100); printf("%d\n", x); return 0; }
注意:
- 您需要使用适当的宏
EM_ASM_INT
或EM_ASM_DOUBLE
来指定返回值是 int 还是 double; - 输入参数使用
$0,$1
等; - return 被用来提供从 JavaScript 发送回 c 的值;
- 使用
{
和}
来封装代码,以便将代码与稍后传递的参数区分开来,后面是输入参数; - 当使用
EM_ASM
宏时,请确保只使用单引号,双引号将导致编译器无法检测到的语法错误
-
js 回调
目标: 在 WebAssembly 端接收并解析 JSON 字符串后,做一些逻辑处理,然后返回修改后的 JSON 字符串
C++ 代码:
#include <emscripten.h>
int jsonParse(const char *jsonStr)
{
auto j = nlohmann::json::parse(jsonStr);
if (j.find("data") != j.end())
{
j["data"] = "Hi there!";
string res = j.dump();
EM_ASM({
if (typeof window.onRspHandler == 'function')
{
window.onRspHandler(UTF8ToString($0))
}
}, res.c_str());
}
return 0;
}
使用 EM_ASM
调用外部 js 的 window.onRspHandler
回调方法。EM_ASM
大括号内可以书写任意的 JavaScript 代码,并且可以对其进行传参操作。在本例中,我们将 result 传递给 EM_ASM 方法,其 $0
为传参的等价替换,若还有更多参数则可以写为 $1、$2
等。
js 代码:
// js 回调函数
window.onRspHandler = (result) => {
console.log(result); // 在控制台输出: {"data":"Hi there!"}
};
const jsonstr = JSON.stringify({data:"Hello Json!"});
const ptr = allocateUTF8(jsonstr);
Module._jsonParse(ptr);
_free(ptr);
参考: