> ## 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.

# 回调

> 通过 JSCallback 将 ArkTS 函数传递给 C 代码

`JSCallback` 包装 ArkTS 函数，使其可作为 C 函数指针使用。

## 基本用法

```typescript theme={null}
const cb = new JSCallback(
  (a: number, b: number): number => a + b,
  { args: [FFIType.int32, FFIType.int32], returns: FFIType.int32 },
);

cb.call(2, 3); // → 5
```

## 闭包捕获

```typescript theme={null}
function makeAdder(x: number): JSCallback {
  return new JSCallback(
    (y: number): number => x + y,
    { args: [FFIType.int32], returns: FFIType.int32 },
  );
}

const add5 = makeAdder(5);
add5.call(3); // → 8
add5.close();
```

## 线程安全

可能从不同线程调用时设置 `threadsafe: true`：

```typescript theme={null}
const cb = new JSCallback(
  (x: number): number => x * 2,
  { args: [FFIType.int32], returns: FFIType.double, threadsafe: true },
);

cb.threadsafe; // → true
cb.call(5);    // → 10
cb.close();
```

### 线程安全与 C 函数指针

`threadsafe: true` 时，`cb.ptr` 返回一个**真实的 C 函数指针**（蹦床地址），可直接传给原生 C 代码：

```typescript theme={null}
const cb = new JSCallback((x: number): number => x * 3, {
  args: [FFIType.int32],
  returns: FFIType.int32,
  threadsafe: true,
});

// cb.ptr 是真实函数地址，可通过 CFunction 包装后调用
const fn = CFunction({ args: [FFIType.int32], returns: FFIType.int32, ptr: cb.ptr });
fn(7); // → 21
fn.close();
cb.close();
```

内部机制：`JSCallback` 创建时通过 `napi_create_threadsafe_function` 创建 TSFN，同时分配 16 个预编译的本机蹦床函数，每个槽位对应一个独立函数地址。`cb.ptr` 通过 `getCallbackPtr` 返回该地址，原生 C 代码调用该地址时会先通过 `TrampolineDispatcher` 同步调用 ArkTS 回调并返回结果。

## 清理

始终调用 `close()` 释放资源：

```typescript theme={null}
cb.close();
cb.call(1); // 抛出异常：句柄无效
```

## 多个回调

```typescript theme={null}
import { JSCallback, FFIType } from 'arkffi';

const add = new JSCallback(fn1, { args: [FFIType.int32, FFIType.int32], returns: FFIType.int32 });
const mul = new JSCallback(fn2, { args: [FFIType.int32, FFIType.int32], returns: FFIType.int32 });

add.call(3, 4); // 7
mul.call(3, 4); // 12

add.close();
mul.close();
```

## 传递给原生函数

```typescript theme={null}
// C: void foreach(int* arr, int len, void (*cb)(int));
const cb = new JSCallback(
  (x: number): number => x * 2,
  { args: [FFIType.int32], returns: FFIType.int32 },
);

ffi.callMixed(handle, 'foreach', 'ipi', 'v', [arrPtr, len, cb.ptr], []);
cb.close();
```
