@ 260902.1raw
current

Thread-safe Functions

JavaScript functions can normally only be called from a native addon’s main thread. If an addon creates additional threads, then node-addon-api functions that require a Napi::Env, Napi::Value, or Napi::Reference must not be called from those threads.

When an addon has additional threads and JavaScript functions need to be invoked based on the processing completed by those threads, those threads must communicate with the addon’s main thread so that the main thread can invoke the JavaScript function on their behalf. The thread-safe function APIs provide an easy way to do this. These APIs provide two types – Napi::ThreadSafeFunction and Napi::TypedThreadSafeFunction – as well as APIs to create, destroy, and call objects of this type. The differences between the two are subtle and are highlighted below. Regardless of which type you choose, the APIs between the two are similar.

Napi::[Typed]ThreadSafeFunction::New() creates a persistent reference that holds a JavaScript function which can be called from multiple threads. The calls happen asynchronously. This means that values with which the JavaScript callback is to be called will be placed in a queue, and, for each value in the queue, a call will eventually be made to the JavaScript function.

Napi::[Typed]ThreadSafeFunction objects are destroyed when every thread which uses the object has called Release() or has received a return status of napi_closing in response to a call to BlockingCall() or NonBlockingCall(). The queue is emptied before the Napi::[Typed]ThreadSafeFunction is destroyed. It is important that Release() be the last API call made in conjunction with a given Napi::[Typed]ThreadSafeFunction, because after the call completes, there is no guarantee that the Napi::[Typed]ThreadSafeFunction is still allocated. For the same reason it is also important that no more use be made of a thread-safe function after receiving a return value of napi_closing in response to a call to BlockingCall() or NonBlockingCall(). Data associated with the Napi::[Typed]ThreadSafeFunction can be freed in its Finalizer callback which was passed to [Typed]ThreadSafeFunction::New().

Once the number of threads making use of a Napi::[Typed]ThreadSafeFunction reaches zero, no further threads can start making use of it by calling Acquire(). In fact, all subsequent API calls associated with it, except Release(), will return an error value of napi_closing.

Implementation Differences

The choice between Napi::ThreadSafeFunction and Napi::TypedThreadSafeFunction depends largely on how you plan to execute your native C++ code (the “callback”) on the Node.js thread.

Napi::ThreadSafeFunction

This API is designed without Node-API 5 native support for the optional JavaScript function callback feature.

This API has some dynamic functionality, in that:

Note that this functionality comes with some additional overhead and situational memory leaks:

Napi::TypedThreadSafeFunction

The TypedThreadSafeFunction class is a new implementation to address the drawbacks listed above. The API is designed with Node-API 5’s support of an optional function callback. The API will correctly allow developers to pass std::nullptr instead of a const Function& for the callback function specified in ::New. It also provides helper APIs to target Node-API 4 and construct a no-op Function or to target Node-API 5 and “construct” a std::nullptr callback. This allows a single codebase to use the same APIs, with just a switch of the NAPI_VERSION compile-time constant.

The removal of the dynamic call functionality has the following implications:

Usage Suggestions

In summary, it may be best to use Napi::TypedThreadSafeFunction if:

Otherwise, Napi::ThreadSafeFunction may be a better choice.