1# Thread-safe Functions
2
3JavaScript functions can normally only be called from a native addon's main
4thread. If an addon creates additional threads, then node-addon-api functions
5that require a `Napi::Env`, `Napi::Value`, or `Napi::Reference` must not be
6called from those threads.
7
8When an addon has additional threads and JavaScript functions need to be invoked
9based on the processing completed by those threads, those threads must
10communicate with the addon's main thread so that the main thread can invoke the
11JavaScript function on their behalf. The thread-safe function APIs provide an
12easy way to do this. These APIs provide two types --
13[`Napi::ThreadSafeFunction`](threadsafe_function.md) and
14[`Napi::TypedThreadSafeFunction`](typed_threadsafe_function.md) -- as well as
15APIs to create, destroy, and call objects of this type. The differences between
16the two are subtle and are [highlighted below](#implementation-differences).
17Regardless of which type you choose, the APIs between the two are similar.
18
19`Napi::[Typed]ThreadSafeFunction::New()` creates a persistent reference that
20holds a JavaScript function which can be called from multiple threads. The calls
21happen asynchronously. This means that values with which the JavaScript callback
22is to be called will be placed in a queue, and, for each value in the queue, a
23call will eventually be made to the JavaScript function.
24
25`Napi::[Typed]ThreadSafeFunction` objects are destroyed when every thread which
26uses the object has called `Release()` or has received a return status of
27`napi_closing` in response to a call to `BlockingCall()` or `NonBlockingCall()`.
28The queue is emptied before the `Napi::[Typed]ThreadSafeFunction` is destroyed.
29It is important that `Release()` be the last API call made in conjunction with a
30given `Napi::[Typed]ThreadSafeFunction`, because after the call completes, there
31is no guarantee that the `Napi::[Typed]ThreadSafeFunction` is still allocated.
32For the same reason it is also important that no more use be made of a
33thread-safe function after receiving a return value of `napi_closing` in
34response to a call to `BlockingCall()` or `NonBlockingCall()`. Data associated
35with the `Napi::[Typed]ThreadSafeFunction` can be freed in its `Finalizer`
36callback which was passed to `[Typed]ThreadSafeFunction::New()`.
37
38Once the number of threads making use of a `Napi::[Typed]ThreadSafeFunction`
39reaches zero, no further threads can start making use of it by calling
40`Acquire()`. In fact, all subsequent API calls associated with it, except
41`Release()`, will return an error value of `napi_closing`.
42
43## Implementation Differences
44
45The choice between `Napi::ThreadSafeFunction` and
46`Napi::TypedThreadSafeFunction` depends largely on how you plan to execute your
47native C++ code (the "callback") on the Node.js thread.
48
49### [`Napi::ThreadSafeFunction`](threadsafe_function.md)
50
51This API is designed without Node-API 5 native support for [the optional JavaScript
52  function callback feature](/node/commit/53297e66cb).
53
54This API has some dynamic functionality, in that:
55- The `[Non]BlockingCall()` methods provide a `Napi::Function` parameter as the
56  callback to run when processing the data item on the main thread -- the
57  `CallJs` callback. Since the callback is a parameter, it can be changed for
58  every call.
59- Different C++ data types may be passed with each call of `[Non]BlockingCall()`
60  to match the specific data type as specified in the `CallJs` callback.
61
62Note that this functionality comes with some **additional overhead** and
63situational **memory leaks**:
64- The API acts as a "broker" between the underlying `napi_threadsafe_function`,
65  and dynamically constructs a wrapper for your callback on the heap for every
66  call to `[Non]BlockingCall()`.
67- In acting in this "broker" fashion, the API will call the underlying "make
68  call" Node-API method on this packaged item. If the API has determined the
69  thread-safe function is no longer accessible (eg. all threads have released
70  yet there are still items on the queue), **the callback passed to
71  [Non]BlockingCall will not execute**. This means it is impossible to perform
72  clean-up for calls that never execute their `CallJs` callback. **This may lead
73  to memory leaks** if you are dynamically allocating memory.
74- The `CallJs` does not receive the thread-safe function's context as a
75  parameter. In order for the callback to access the context, it must have a
76  reference to either (1) the context directly, or (2) the thread-safe function
77  to call `GetContext()`. Furthermore, the `GetContext()` method is not
78  _type-safe_, as the method returns an object that can be "any-casted", instead
79  of having a static type.
80
81### [`Napi::TypedThreadSafeFunction`](typed_threadsafe_function.md)
82
83The `TypedThreadSafeFunction` class is a new implementation to address the
84drawbacks listed above. The API is designed with Node-API 5's support of an
85optional function callback. The API will correctly allow developers to pass
86`std::nullptr` instead of a `const Function&` for the callback function
87specified in `::New`. It also provides helper APIs to _target_ Node-API 4 and
88construct a no-op `Function` **or** to target Node-API 5 and "construct" a
89`std::nullptr` callback. This allows a single codebase to use the same APIs,
90with just a switch of the `NAPI_VERSION` compile-time constant.
91
92The removal of the dynamic call functionality has the following implications:
93- The API does _not_ act as a "broker" compared to the
94  `Napi::ThreadSafeFunction`. Once Node.js finalizes the thread-safe function,
95  the `CallJs` callback will execute with an empty `Napi::Env` for any remaining
96  items on the queue. This provides the ability to handle any necessary cleanup
97  of the item's data.
98- The callback _does_ receive the context as a parameter, so a call to
99  `GetContext()` is _not_ necessary. This context type is specified as the
100  **first template argument** specified to `::New`, ensuring type safety.
101- The `New()` constructor accepts the `CallJs` callback as the **second type
102  argument**. The callback must be statically defined for the API to access it.
103  This affords the ability to statically pass the context as the correct type
104  across all methods.
105- Only one C++ data type may be specified to every call to `[Non]BlockingCall()`
106  -- the **third template argument** specified to `::New`. Any "dynamic call
107  data" must be implemented by the user.
108
109
110### Usage Suggestions
111
112In summary, it may be best to use `Napi::TypedThreadSafeFunction` if:
113
114- static, compile-time support for targeting Node-API 4 or 5+ with an optional
115  JavaScript callback feature is desired;
116- the callback can have `static` storage class and will not change across calls
117  to `[Non]BlockingCall()`;
118- cleanup of items' data is required (eg. deleting dynamically-allocated data
119  that is created at the caller level).
120
121Otherwise, `Napi::ThreadSafeFunction` may be a better choice.
122