> ## 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();
```
