Skip to main content

Async Function Pointers

Ordinary JavaScript function objects cannot be serialized across Roku SceneGraph node or task boundaries. AsyncFunctionPointer<T> tells the Hosanna Compiler to encode an exported module function as a resolvable string pointer.

Use this type only where an API explicitly carries behavior across an asynchronous boundary. HsFetchOptions.postProcessFunction is the common example. Programmatic AppConfig fragment callback arrays are another supported slot: they can contain exported async-function pointers directly, registered callback names, or both.

Compile-time, Roku-boundary, and Web-compatibility lanes for validating, serializing, resolving, and invoking AsyncFunctionPointer valuesCompile-time, Roku-boundary, and Web-compatibility lanes for validating, serializing, resolving, and invoking AsyncFunctionPointer values

Define an exported handler

import type { IHsFetchResponse } from '@hs-src/hosanna-bridge-core/api';

export function processResponse(response: IHsFetchResponse): void {
console.info('Response processed:', response.ok);
}

Then pass the reference to the typed slot:

this.dispatch(Http.Get, {
url: 'https://api.example.com/data',
postProcessFunction: processResponse,
contextData: { requestKey: 'home' }
});

The HTTP command handler attaches contextData to the response and resolves the pointer before invoking it.

Keep the function serializable

The referenced function must be:

  • declared at module scope;
  • exported;
  • referenced by its identifier;
  • callable without captured local variables or a captured this; and
  • compatible with the typed callback signature.

These are invalid:

// Inline function: no exported module identity
const options = {
postProcessFunction: (response: IHsFetchResponse) => {
this.consume(response);
}
};

// Bound instance method: captures an object
const options2 = {
postProcessFunction: this.consume.bind(this)
};

The compiler emits HS-1094 for invalid pointer values, and the Hosanna linter also checks inline functions, bound values, instance members, and indirect references in AsyncFunctionPointer contexts.

Preserve the signature

The global type is generic:

type RowHandler = AsyncFunctionPointer<(rowId: string, index: number) => void>;

export function handleRow(rowId: string, index: number): void {
console.info(rowId, index);
}

const handler: RowHandler = handleRow;

Using AsyncFunctionPointer<(...) => ...> retains TypeScript checking at the call site. An unparameterized AsyncFunctionPointer remains available for legacy APIs but gives weaker checking.

Resolve a pointer

Framework code on the receiving side calls:

const resolved = hs_resolveAsyncFunctionPointer(handler);
resolved('featured', 0);

On Roku the compiler serialized handler as a module-and-function string. The runtime finds that module function and returns a wrapper with the module context needed by generated code. On web, the compatibility implementation returns a function reference.

Do not resolve arbitrary strings. A missing module, missing function, malformed pointer, or non-pointer input fails at runtime.

Runtime limits

  • The Roku wrapper accepts zero to five positional arguments. More than five throws.
  • Closures and instance state are not serialized.
  • Pointer identity depends on an exported module function remaining present in the compiled output.
  • An async exported function can return its normal Hosanna promise, but its arguments are subject to the same serialization and arity constraints.

When a callback needs object state, pass serializable context data and look up shared services or state inside the exported handler. Do not attempt to smuggle the owning instance through .bind, .call, or a closure.

For a runnable reference, see rigs/async/PostProcessFunctionRig.ts in hosanna-ui-samples-public.

Talk to us