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

# Callbacks

> Passing TypeScript functions to C code via JSCallback

`JSCallback` wraps TypeScript functions so they can be used as C function pointers.

## Basic Usage

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

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

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

## Closure Capture

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

## Thread Safety

Set `threadsafe: true` for callbacks that may be invoked from a different thread:

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

### Thread-Safe C Function Pointers

When `threadsafe: true`, `cb.ptr` returns a **real C function pointer** (trampoline address) that can be passed directly to native C code:

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

const fn = CFunction({ args: [FFIType.int32], returns: FFIType.int32, ptr: cb.ptr });
fn(7); // → 21
fn.close();
cb.close();
```

Internally, `napi_create_threadsafe_function` creates a TSFN, while 16 pre-compiled native trampoline functions are allocated — one per callback slot. `cb.ptr` returns the trampoline address via `getCallbackPtr`. When native C code calls this address, `TrampolineDispatcher` synchronously invokes the TypeScript callback and returns the result.

## Cleanup

Always call `close()` to release resources:

```typescript theme={null}
cb.close();
cb.call(1); // throws: invalid handle
```

## Multiple Callbacks

```typescript theme={null}
const add = new JSCallback(fn1, { args: ['i', 'i'], returns: 'i' });
const mul = new JSCallback(fn2, { args: ['i', 'i'], returns: 'i' });

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

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

## Passing to Native Functions

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