同步 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註冊