同步 vs 异步
arkffi 默认的 C 函数调用是同步的——lib.symbols.add(2.0, 3.0) 会阻塞当前线程直到函数返回。
对于耗时操作(复杂计算、I/O),可以使用 callAsync 将调用卸载到 libuv 工作线程,返回一个 Promise。
ffi.callAsync
语法
参数
| 参数 | 类型 | 说明 |
|---|---|---|
handle | bigint | ffi.load() 返回的库句柄 |
funcName | string | 函数名(必须已通过 defineFunction 注册) |
argTypes | string | 参数类型编码 |
returnType | string | 返回类型编码 |
numArgs | number[] | 数值参数 |
strArgs | string[] | 字符串参数 |
AsyncCFunction
AsyncCFunction 是 CFunction 的异步版本,签名完全一致,但返回 Promise<number>。不需要通过 defineFunction 注册,直接使用函数指针:
对比
| 特性 | CFunction | AsyncCFunction |
|---|---|---|
| 返回值 | number(同步) | Promise<number>(异步) |
| 阻塞主线程 | ✅ 是 | ❌ 否 |
是否需要 defineFunction | ❌ 不需要 | ❌ 不需要 |
| 参数类型支持 | 全部 | 全部 |
| 关闭方法 | .close() | .close() |
与 dlopen 配合使用
函数必须通过 defineFunction 注册到注册表后才能异步调用:
实现原理
callAsync在 JS 线程解析参数并创建napi_async_work- 工作线程上执行
DispatchCallRaw——纯 C 函数指针调用,不涉及 NAPI - 完成后在 JS 线程上 resolve Promise
- 整个过程中 JS 主线程不被阻塞
限制
- 不支持字符串返回类型(
callString无异步版本) - 回调函数(
JSCallback)不能在异步工作线程中调用 - 必须先将函数通过
defineFunction注册