18c339a94Sopenharmony_ci# Thread-safe Functions
28c339a94Sopenharmony_ci
38c339a94Sopenharmony_ciJavaScript functions can normally only be called from a native addon's main
48c339a94Sopenharmony_cithread. If an addon creates additional threads, then node-addon-api functions
58c339a94Sopenharmony_cithat require a `Napi::Env`, `Napi::Value`, or `Napi::Reference` must not be
68c339a94Sopenharmony_cicalled from those threads.
78c339a94Sopenharmony_ci
88c339a94Sopenharmony_ciWhen an addon has additional threads and JavaScript functions need to be invoked
98c339a94Sopenharmony_cibased on the processing completed by those threads, those threads must
108c339a94Sopenharmony_cicommunicate with the addon's main thread so that the main thread can invoke the
118c339a94Sopenharmony_ciJavaScript function on their behalf. The thread-safe function APIs provide an
128c339a94Sopenharmony_cieasy way to do this. These APIs provide two types --
138c339a94Sopenharmony_ci[`Napi::ThreadSafeFunction`](threadsafe_function.md) and
148c339a94Sopenharmony_ci[`Napi::TypedThreadSafeFunction`](typed_threadsafe_function.md) -- as well as
158c339a94Sopenharmony_ciAPIs to create, destroy, and call objects of this type. The differences between
168c339a94Sopenharmony_cithe two are subtle and are [highlighted below](#implementation-differences).
178c339a94Sopenharmony_ciRegardless of which type you choose, the APIs between the two are similar.
188c339a94Sopenharmony_ci
198c339a94Sopenharmony_ci`Napi::[Typed]ThreadSafeFunction::New()` creates a persistent reference that
208c339a94Sopenharmony_ciholds a JavaScript function which can be called from multiple threads. The calls
218c339a94Sopenharmony_cihappen asynchronously. This means that values with which the JavaScript callback
228c339a94Sopenharmony_ciis to be called will be placed in a queue, and, for each value in the queue, a
238c339a94Sopenharmony_cicall will eventually be made to the JavaScript function.
248c339a94Sopenharmony_ci
258c339a94Sopenharmony_ci`Napi::[Typed]ThreadSafeFunction` objects are destroyed when every thread which
268c339a94Sopenharmony_ciuses the object has called `Release()` or has received a return status of
278c339a94Sopenharmony_ci`napi_closing` in response to a call to `BlockingCall()` or `NonBlockingCall()`.
288c339a94Sopenharmony_ciThe queue is emptied before the `Napi::[Typed]ThreadSafeFunction` is destroyed.
298c339a94Sopenharmony_ciIt is important that `Release()` be the last API call made in conjunction with a
308c339a94Sopenharmony_cigiven `Napi::[Typed]ThreadSafeFunction`, because after the call completes, there
318c339a94Sopenharmony_ciis no guarantee that the `Napi::[Typed]ThreadSafeFunction` is still allocated.
328c339a94Sopenharmony_ciFor the same reason it is also important that no more use be made of a
338c339a94Sopenharmony_cithread-safe function after receiving a return value of `napi_closing` in
348c339a94Sopenharmony_ciresponse to a call to `BlockingCall()` or `NonBlockingCall()`. Data associated
358c339a94Sopenharmony_ciwith the `Napi::[Typed]ThreadSafeFunction` can be freed in its `Finalizer`
368c339a94Sopenharmony_cicallback which was passed to `[Typed]ThreadSafeFunction::New()`.
378c339a94Sopenharmony_ci
388c339a94Sopenharmony_ciOnce the number of threads making use of a `Napi::[Typed]ThreadSafeFunction`
398c339a94Sopenharmony_cireaches zero, no further threads can start making use of it by calling
408c339a94Sopenharmony_ci`Acquire()`. In fact, all subsequent API calls associated with it, except
418c339a94Sopenharmony_ci`Release()`, will return an error value of `napi_closing`.
428c339a94Sopenharmony_ci
438c339a94Sopenharmony_ci## Implementation Differences
448c339a94Sopenharmony_ci
458c339a94Sopenharmony_ciThe choice between `Napi::ThreadSafeFunction` and
468c339a94Sopenharmony_ci`Napi::TypedThreadSafeFunction` depends largely on how you plan to execute your
478c339a94Sopenharmony_cinative C++ code (the "callback") on the Node.js thread.
488c339a94Sopenharmony_ci
498c339a94Sopenharmony_ci### [`Napi::ThreadSafeFunction`](threadsafe_function.md)
508c339a94Sopenharmony_ci
518c339a94Sopenharmony_ciThis API is designed without Node-API 5 native support for [the optional JavaScript
528c339a94Sopenharmony_ci  function callback feature](/node/commit/53297e66cb).
538c339a94Sopenharmony_ci
548c339a94Sopenharmony_ciThis API has some dynamic functionality, in that:
558c339a94Sopenharmony_ci- The `[Non]BlockingCall()` methods provide a `Napi::Function` parameter as the
568c339a94Sopenharmony_ci  callback to run when processing the data item on the main thread -- the
578c339a94Sopenharmony_ci  `CallJs` callback. Since the callback is a parameter, it can be changed for
588c339a94Sopenharmony_ci  every call.
598c339a94Sopenharmony_ci- Different C++ data types may be passed with each call of `[Non]BlockingCall()`
608c339a94Sopenharmony_ci  to match the specific data type as specified in the `CallJs` callback.
618c339a94Sopenharmony_ci
628c339a94Sopenharmony_ciNote that this functionality comes with some **additional overhead** and
638c339a94Sopenharmony_cisituational **memory leaks**:
648c339a94Sopenharmony_ci- The API acts as a "broker" between the underlying `napi_threadsafe_function`,
658c339a94Sopenharmony_ci  and dynamically constructs a wrapper for your callback on the heap for every
668c339a94Sopenharmony_ci  call to `[Non]BlockingCall()`.
678c339a94Sopenharmony_ci- In acting in this "broker" fashion, the API will call the underlying "make
688c339a94Sopenharmony_ci  call" Node-API method on this packaged item. If the API has determined the
698c339a94Sopenharmony_ci  thread-safe function is no longer accessible (eg. all threads have released
708c339a94Sopenharmony_ci  yet there are still items on the queue), **the callback passed to
718c339a94Sopenharmony_ci  [Non]BlockingCall will not execute**. This means it is impossible to perform
728c339a94Sopenharmony_ci  clean-up for calls that never execute their `CallJs` callback. **This may lead
738c339a94Sopenharmony_ci  to memory leaks** if you are dynamically allocating memory.
748c339a94Sopenharmony_ci- The `CallJs` does not receive the thread-safe function's context as a
758c339a94Sopenharmony_ci  parameter. In order for the callback to access the context, it must have a
768c339a94Sopenharmony_ci  reference to either (1) the context directly, or (2) the thread-safe function
778c339a94Sopenharmony_ci  to call `GetContext()`. Furthermore, the `GetContext()` method is not
788c339a94Sopenharmony_ci  _type-safe_, as the method returns an object that can be "any-casted", instead
798c339a94Sopenharmony_ci  of having a static type.
808c339a94Sopenharmony_ci
818c339a94Sopenharmony_ci### [`Napi::TypedThreadSafeFunction`](typed_threadsafe_function.md)
828c339a94Sopenharmony_ci
838c339a94Sopenharmony_ciThe `TypedThreadSafeFunction` class is a new implementation to address the
848c339a94Sopenharmony_cidrawbacks listed above. The API is designed with Node-API 5's support of an
858c339a94Sopenharmony_cioptional function callback. The API will correctly allow developers to pass
868c339a94Sopenharmony_ci`std::nullptr` instead of a `const Function&` for the callback function
878c339a94Sopenharmony_cispecified in `::New`. It also provides helper APIs to _target_ Node-API 4 and
888c339a94Sopenharmony_ciconstruct a no-op `Function` **or** to target Node-API 5 and "construct" a
898c339a94Sopenharmony_ci`std::nullptr` callback. This allows a single codebase to use the same APIs,
908c339a94Sopenharmony_ciwith just a switch of the `NAPI_VERSION` compile-time constant.
918c339a94Sopenharmony_ci
928c339a94Sopenharmony_ciThe removal of the dynamic call functionality has the following implications:
938c339a94Sopenharmony_ci- The API does _not_ act as a "broker" compared to the
948c339a94Sopenharmony_ci  `Napi::ThreadSafeFunction`. Once Node.js finalizes the thread-safe function,
958c339a94Sopenharmony_ci  the `CallJs` callback will execute with an empty `Napi::Env` for any remaining
968c339a94Sopenharmony_ci  items on the queue. This provides the ability to handle any necessary cleanup
978c339a94Sopenharmony_ci  of the item's data.
988c339a94Sopenharmony_ci- The callback _does_ receive the context as a parameter, so a call to
998c339a94Sopenharmony_ci  `GetContext()` is _not_ necessary. This context type is specified as the
1008c339a94Sopenharmony_ci  **first template argument** specified to `::New`, ensuring type safety.
1018c339a94Sopenharmony_ci- The `New()` constructor accepts the `CallJs` callback as the **second type
1028c339a94Sopenharmony_ci  argument**. The callback must be statically defined for the API to access it.
1038c339a94Sopenharmony_ci  This affords the ability to statically pass the context as the correct type
1048c339a94Sopenharmony_ci  across all methods.
1058c339a94Sopenharmony_ci- Only one C++ data type may be specified to every call to `[Non]BlockingCall()`
1068c339a94Sopenharmony_ci  -- the **third template argument** specified to `::New`. Any "dynamic call
1078c339a94Sopenharmony_ci  data" must be implemented by the user.
1088c339a94Sopenharmony_ci
1098c339a94Sopenharmony_ci
1108c339a94Sopenharmony_ci### Usage Suggestions
1118c339a94Sopenharmony_ci
1128c339a94Sopenharmony_ciIn summary, it may be best to use `Napi::TypedThreadSafeFunction` if:
1138c339a94Sopenharmony_ci
1148c339a94Sopenharmony_ci- static, compile-time support for targeting Node-API 4 or 5+ with an optional
1158c339a94Sopenharmony_ci  JavaScript callback feature is desired;
1168c339a94Sopenharmony_ci- the callback can have `static` storage class and will not change across calls
1178c339a94Sopenharmony_ci  to `[Non]BlockingCall()`;
1188c339a94Sopenharmony_ci- cleanup of items' data is required (eg. deleting dynamically-allocated data
1198c339a94Sopenharmony_ci  that is created at the caller level).
1208c339a94Sopenharmony_ci
1218c339a94Sopenharmony_ciOtherwise, `Napi::ThreadSafeFunction` may be a better choice.
122