> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arkffi.hmbill.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 异步调用

> 在不阻塞 JS 线程的情况下调用原生 C 函数

## 同步 vs 异步

arkffi 默认的 C 函数调用是**同步**的——`lib.symbols.add(2.0, 3.0)` 会阻塞当前线程直到函数返回。

对于耗时操作（复杂计算、I/O），可以使用 **`callAsync`** 将调用卸载到 libuv 工作线程，返回一个 Promise。

## `ffi.callAsync`

```typescript theme={null}
import ffi from 'liblibrary.so';

const handle = ffi.load('libffi_target.so');
ffi.defineFunction(handle, 'factorial', 'i', 'l');

ffi.callAsync(handle, 'factorial', 'i', 'l', [10], []).then((r: number) => {
  console.log(r); // 3628800
  ffi.close(handle);
});
```

### 语法

```typescript theme={null}
function callAsync(
  handle: bigint,
  funcName: string,
  argTypes: string,
  returnType: string,
  numArgs: number[],
  strArgs: string[],
): Promise<number>;
```

### 参数

| 参数           | 类型         | 说明                             |
| ------------ | ---------- | ------------------------------ |
| `handle`     | `bigint`   | `ffi.load()` 返回的库句柄            |
| `funcName`   | `string`   | 函数名（必须已通过 `defineFunction` 注册） |
| `argTypes`   | `string`   | 参数类型编码                         |
| `returnType` | `string`   | 返回类型编码                         |
| `numArgs`    | `number[]` | 数值参数                           |
| `strArgs`    | `string[]` | 字符串参数                          |

## `AsyncCFunction`

`AsyncCFunction` 是 `CFunction` 的异步版本，签名完全一致，但返回 `Promise<number>`。不需要通过 `defineFunction` 注册，直接使用函数指针：

```typescript theme={null}
import { AsyncCFunction, FFIType } from 'arkffi';
import ffi from 'liblibrary.so';

const handle = ffi.load('libffi_target.so');
const addPtr = ffi.getSymbolPtr(handle, 'add');

const asyncAdd = AsyncCFunction({
  args: [FFIType.double, FFIType.double],
  returns: FFIType.double,
  ptr: addPtr,
});

// 通过 .then 获取结果
asyncAdd(2.0, 3.0).then((r: number) => {
  console.log(r); // 5.0
});

// 多个调用并发执行
Promise.all([asyncAdd(1.0, 2.0), asyncAdd(3.0, 4.0)]).then((results) => {
  console.log(results); // [3.0, 7.0]
});

asyncAdd.close();
ffi.close(handle);
```

### 对比

| 特性                    | `CFunction`  | `AsyncCFunction`      |
| --------------------- | ------------ | --------------------- |
| 返回值                   | `number`（同步） | `Promise<number>`（异步） |
| 阻塞主线程                 | ✅ 是          | ❌ 否                   |
| 是否需要 `defineFunction` | ❌ 不需要        | ❌ 不需要                 |
| 参数类型支持                | 全部           | 全部                    |
| 关闭方法                  | `.close()`   | `.close()`            |

## 与 `dlopen` 配合使用

```typescript theme={null}
const Complex = Struct({
  real: FFIType.double,
  imag: FFIType.double,
});
const LibFFT = dlopen(LIB_NAME_FFT, {
  complex_new: { args: [FFIType.double, FFIType.double], returns: Complex },
  complex_add: { args: [Complex, Complex], returns: Complex },
  complex_sub: { args: [Complex, Complex], returns: Complex },
  complex_mul: { args: [Complex, Complex], returns: Complex },
  fft: { args: [FFIType.ptr, FFIType.int32], returns: FFIType.void }
});

let a = Complex.create({ real: 4, imag: 1 });
let b = Complex.create({ real: 3, imag: 3 });
LibFFT.symbols.complex_mul.async(a, b)
  .then((mulPtr) => {
    let mulVal = Complex.fromPtr(mulPtr);
    console.log('complex_mul', mulVal.real, mulVal.imag);
  })
  .finally(() => {
    LibFFT.close();
  });
console.log('LibFFT.symbols.complex_mul.async');
```

## 实现原理

1. `callAsync` 在 JS 线程解析参数并创建 `napi_async_work`
2. 工作线程上执行 `DispatchCallRaw`——纯 C 函数指针调用，不涉及 NAPI
3. 完成后在 JS 线程上 resolve Promise
4. 整个过程中 JS 主线程不被阻塞

## 限制

* 不支持字符串返回类型（`callString` 无异步版本）
* 回调函数（`JSCallback`）不能在异步工作线程中调用
* 必须先将函数通过 `defineFunction` 注册
