node-addon-api 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -243,7 +243,9 @@ be safely released.
243
243
  Note that `Napi::AsyncProgressWorker::ExecutionProcess::Send` merely guarantees
244
244
  **eventual** invocation of `Napi::AsyncProgressWorker::OnProgress`, which means
245
245
  multiple send might be coalesced into single invocation of `Napi::AsyncProgressWorker::OnProgress`
246
- with latest data.
246
+ with latest data. If you would like to guarantee that there is one invocation of
247
+ `OnProgress` for every `Send` call, you should use the `Napi::AsyncProgressQueueWorker`
248
+ class instead which is documented further down this page.
247
249
 
248
250
  ```cpp
249
251
  void Napi::AsyncProgressWorker::ExecutionProcess::Send(const T* data, size_t count) const;
@@ -269,7 +271,8 @@ function runs in the background out of the **event loop** thread and at the end
269
271
  the `Napi::AsyncProgressWorker::OnOK` or `Napi::AsyncProgressWorker::OnError` function will be
270
272
  called and are executed as part of the event loop.
271
273
 
272
- The code below shows a basic example of the `Napi::AsyncProgressWorker` implementation:
274
+ The code below shows a basic example of the `Napi::AsyncProgressWorker` implementation along with an
275
+ example of how the counterpart in Javascript would appear:
273
276
 
274
277
  ```cpp
275
278
  #include <napi.h>
@@ -281,28 +284,38 @@ using namespace Napi;
281
284
 
282
285
  class EchoWorker : public AsyncProgressWorker<uint32_t> {
283
286
  public:
284
- EchoWorker(Function& callback, std::string& echo)
285
- : AsyncProgressWorker(callback), echo(echo) {}
287
+ EchoWorker(Function& okCallback, std::string& echo)
288
+ : AsyncProgressWorker(okCallback), echo(echo) {}
286
289
 
287
290
  ~EchoWorker() {}
288
- // This code will be executed on the worker thread
289
- void Execute(const ExecutionProgress& progress) {
290
- // Need to simulate cpu heavy task
291
- for (uint32_t i = 0; i < 100; ++i) {
292
- progress.Send(&i, 1)
293
- std::this_thread::sleep_for(std::chrono::seconds(1));
291
+
292
+ // This code will be executed on the worker thread
293
+ void Execute(const ExecutionProgress& progress) {
294
+ // Need to simulate cpu heavy task
295
+ // Note: This Send() call is not guaranteed to trigger an equal
296
+ // number of OnProgress calls (read documentation above for more info)
297
+ for (uint32_t i = 0; i < 100; ++i) {
298
+ progress.Send(&i, 1)
299
+ }
300
+ }
301
+
302
+ void OnError(const Error &e) {
303
+ HandleScope scope(Env());
304
+ // Pass error onto JS, no data for other parameters
305
+ Callback().Call({String::New(Env(), e.Message())});
294
306
  }
295
- }
296
307
 
297
- void OnOK() {
298
- HandleScope scope(Env());
299
- Callback().Call({Env().Null(), String::New(Env(), echo)});
300
- }
308
+ void OnOK() {
309
+ HandleScope scope(Env());
310
+ // Pass no error, give back original data
311
+ Callback().Call({Env().Null(), String::New(Env(), echo)});
312
+ }
301
313
 
302
- void OnProgress(const uint32_t* data, size_t /* count */) {
303
- HandleScope scope(Env());
304
- Callback().Call({Env().Null(), Env().Null(), Number::New(Env(), *data)});
305
- }
314
+ void OnProgress(const uint32_t* data, size_t /* count */) {
315
+ HandleScope scope(Env());
316
+ // Pass no error, no echo data, but do pass on the progress data
317
+ Callback().Call({Env().Null(), Env().Null(), Number::New(Env(), *data)});
318
+ }
306
319
 
307
320
  private:
308
321
  std::string echo;
@@ -327,12 +340,23 @@ using namespace Napi;
327
340
 
328
341
  Value Echo(const CallbackInfo& info) {
329
342
  // We need to validate the arguments here
330
- Function cb = info[1].As<Function>();
331
343
  std::string in = info[0].As<String>();
344
+ Function cb = info[1].As<Function>();
332
345
  EchoWorker* wk = new EchoWorker(cb, in);
333
346
  wk->Queue();
334
347
  return info.Env().Undefined();
335
348
  }
349
+
350
+ // Register the native method for JS to access
351
+ Object Init(Env env, Object exports)
352
+ {
353
+ exports.Set(String::New(env, "echo"), Function::New(env, Echo));
354
+
355
+ return exports;
356
+ }
357
+
358
+ // Register our native addon
359
+ NODE_API_MODULE(nativeAddon, Init)
336
360
  ```
337
361
 
338
362
  The implementation of a `Napi::AsyncProgressWorker` can be used by creating a
@@ -341,6 +365,20 @@ asynchronous task ends and other data needed for the computation. Once created,
341
365
  the only other action needed is to call the `Napi::AsyncProgressWorker::Queue`
342
366
  method that will queue the created worker for execution.
343
367
 
368
+ Lastly, the following Javascript (ES6+) code would be associated the above example:
369
+
370
+ ```js
371
+ const { nativeAddon } = require('binding.node');
372
+
373
+ const exampleCallback = (errorResponse, okResponse, progressData) => {
374
+ // Use the data accordingly
375
+ // ...
376
+ };
377
+
378
+ // Call our native addon with the paramters of a string and a function
379
+ nativeAddon.echo("example", exampleCallback);
380
+ ```
381
+
344
382
  # AsyncProgressQueueWorker
345
383
 
346
384
  `Napi::AsyncProgressQueueWorker` acts exactly like `Napi::AsyncProgressWorker`
@@ -379,7 +417,9 @@ void Napi::AsyncProgressQueueWorker::ExecutionProcess::Send(const T* data, size_
379
417
 
380
418
  ## Example
381
419
 
382
- The code below shows a basic example of the `Napi::AsyncProgressQueueWorker` implementation:
420
+ The code below show an example of the `Napi::AsyncProgressQueueWorker` implementation, but
421
+ also demonsrates how to use multiple `Napi::Function`'s if you wish to provide multiple
422
+ callback functions for more object oriented code:
383
423
 
384
424
  ```cpp
385
425
  #include <napi.h>
@@ -391,31 +431,55 @@ using namespace Napi;
391
431
 
392
432
  class EchoWorker : public AsyncProgressQueueWorker<uint32_t> {
393
433
  public:
394
- EchoWorker(Function& callback, std::string& echo)
395
- : AsyncProgressQueueWorker(callback), echo(echo) {}
434
+ EchoWorker(Function& okCallback, Function& errorCallback, Function& progressCallback, std::string& echo)
435
+ : AsyncProgressQueueWorker(okCallback), echo(echo) {
436
+ // Set our function references to use them below
437
+ this->errorCallback.Reset(errorCallback, 1);
438
+ this->progressCallback.Reset(progressCallback, 1);
439
+ }
396
440
 
397
441
  ~EchoWorker() {}
398
- // This code will be executed on the worker thread
399
- void Execute(const ExecutionProgress& progress) {
400
- // Need to simulate cpu heavy task
401
- for (uint32_t i = 0; i < 100; ++i) {
402
- progress.Send(&i, 1);
403
- std::this_thread::sleep_for(std::chrono::seconds(1));
442
+
443
+ // This code will be executed on the worker thread
444
+ void Execute(const ExecutionProgress& progress) {
445
+ // Need to simulate cpu heavy task to demonstrate that
446
+ // every call to Send() will trigger an OnProgress function call
447
+ for (uint32_t i = 0; i < 100; ++i) {
448
+ progress.Send(&i, 1);
449
+ }
404
450
  }
405
- }
406
451
 
407
- void OnOK() {
408
- HandleScope scope(Env());
409
- Callback().Call({Env().Null(), String::New(Env(), echo)});
410
- }
452
+ void OnOK() {
453
+ HandleScope scope(Env());
454
+ // Call our onOkCallback in javascript with the data we were given originally
455
+ Callback().Call({String::New(Env(), echo)});
456
+ }
457
+
458
+ void OnError(const Error &e) {
459
+ HandleScope scope(Env());
460
+
461
+ // We call our callback provided in the constructor with 2 parameters
462
+ if (!this->errorCallback.IsEmpty()) {
463
+ // Call our onErrorCallback in javascript with the error message
464
+ this->errorCallback.Call(Receiver().Value(), {String::New(Env(), e.Message())});
465
+ }
466
+ }
411
467
 
412
- void OnProgress(const uint32_t* data, size_t /* count */) {
413
- HandleScope scope(Env());
414
- Callback().Call({Env().Null(), Env().Null(), Number::New(Env(), *data)});
415
- }
468
+ void OnProgress(const uint32_t* data, size_t /* count */) {
469
+ HandleScope scope(Env());
470
+
471
+ if (!this->progressCallback.IsEmpty()) {
472
+ // Call our onProgressCallback in javascript with each integer from 0 to 99 (inclusive)
473
+ // as this function is triggered from the above Send() calls
474
+ this->progressCallback.Call(Receiver().Value(), {Number::New(Env(), *data)});
475
+ }
476
+ }
416
477
 
417
478
  private:
418
479
  std::string echo;
480
+ FunctionReference progressCallback;
481
+ FunctionReference errorCallback;
482
+
419
483
  };
420
484
  ```
421
485
 
@@ -439,12 +503,25 @@ using namespace Napi;
439
503
 
440
504
  Value Echo(const CallbackInfo& info) {
441
505
  // We need to validate the arguments here.
442
- Function cb = info[1].As<Function>();
443
506
  std::string in = info[0].As<String>();
444
- EchoWorker* wk = new EchoWorker(cb, in);
507
+ Function errorCb = info[1].As<Function>();
508
+ Function okCb = info[2].As<Function>();
509
+ Function progressCb = info[3].As<Function>();
510
+ EchoWorker* wk = new EchoWorker(okCb, errorCb, progressCb, in);
445
511
  wk->Queue();
446
512
  return info.Env().Undefined();
447
513
  }
514
+
515
+ // Register the native method for JS to access
516
+ Object Init(Env env, Object exports)
517
+ {
518
+ exports.Set(String::New(env, "echo"), Function::New(env, Echo));
519
+
520
+ return exports;
521
+ }
522
+
523
+ // Register our native addon
524
+ NODE_API_MODULE(nativeAddon, Init)
448
525
  ```
449
526
 
450
527
  The implementation of a `Napi::AsyncProgressQueueWorker` can be used by creating a
@@ -453,4 +530,28 @@ asynchronous task ends and other data needed for the computation. Once created,
453
530
  the only other action needed is to call the `Napi::AsyncProgressQueueWorker::Queue`
454
531
  method that will queue the created worker for execution.
455
532
 
533
+ Lastly, the following Javascript (ES6+) code would be associated the above example:
534
+
535
+ ```js
536
+ const { nativeAddon } = require('binding.node');
537
+
538
+ const onErrorCallback = (msg) => {
539
+ // Use the data accordingly
540
+ // ...
541
+ };
542
+
543
+ const onOkCallback = (echo) => {
544
+ // Use the data accordingly
545
+ // ...
546
+ };
547
+
548
+ const onProgressCallback = (num) => {
549
+ // Use the data accordingly
550
+ // ...
551
+ };
552
+
553
+ // Call our native addon with the paramters of a string and three callback functions
554
+ nativeAddon.echo("example", onErrorCallback, onOkCallback, onProgressCallback);
555
+ ```
556
+
456
557
  [`Napi::AsyncWorker`]: ./async_worker.md
package/doc/boolean.md CHANGED
@@ -18,7 +18,7 @@ Napi::Boolean::Boolean();
18
18
 
19
19
  Returns a new _empty_ `Napi::Boolean` object.
20
20
 
21
- ### Contructor
21
+ ### Constructor
22
22
 
23
23
  Creates a new instance of the `Napi::Boolean` object.
24
24
 
@@ -26,7 +26,7 @@ indicating for each addon whether it is an N-API addon.
26
26
  ```
27
27
 
28
28
  The tool accepts the root directory from which to start checking for Node.js
29
- native addons as a single optional command line parameter. If ommitted it will
29
+ native addons as a single optional command line parameter. If omitted it will
30
30
  start checking from the current directory (`.`).
31
31
 
32
32
  [checker tool]: ../tools/check-napi.js
@@ -36,7 +36,7 @@ the route folder of the repo launch the following command:
36
36
  ```bash
37
37
  > changelog-maker
38
38
  ```
39
- * Use the output generated by **changelog maker** to pdate the [CHANGELOG.md](https://github.com/nodejs/node-addon-api/blob/master/CHANGELOG.md)
39
+ * Use the output generated by **changelog maker** to update the [CHANGELOG.md](https://github.com/nodejs/node-addon-api/blob/master/CHANGELOG.md)
40
40
  following the style used in publishing the previous release.
41
41
 
42
42
  * Add any new contributors to the "contributors" section in the package.json
package/doc/error.md CHANGED
@@ -117,4 +117,4 @@ Returns a pointer to a null-terminated string that is used to identify the
117
117
  exception. This method can be used only if the exception mechanism is enabled.
118
118
 
119
119
  [`Napi::ObjectReference`]: ./object_reference.md
120
- [`std::exception`]: http://cplusplus.com/reference/exception/exception/
120
+ [`std::exception`]: https://cplusplus.com/reference/exception/exception/
@@ -59,7 +59,7 @@ Napi::EscapableHandleScope::~EscapableHandleScope();
59
59
 
60
60
  Deletes the `Napi::EscapableHandleScope` instance and allows any objects/handles created
61
61
  in the scope to be collected by the garbage collector. There is no
62
- guarantee as to when the gargbage collector will do this.
62
+ guarantee as to when the garbage collector will do this.
63
63
 
64
64
  ### Escape
65
65
 
package/doc/function.md CHANGED
@@ -218,7 +218,7 @@ Napi::Object Napi::Function::New(const std::initializer_list<napi_value>& args)
218
218
  ```
219
219
 
220
220
  - `[in] args`: Initializer list of JavaScript values as `napi_value` representing
221
- the arguments of the contructor function.
221
+ the arguments of the constructor function.
222
222
 
223
223
  Returns a new JavaScript object.
224
224
 
@@ -245,7 +245,7 @@ object.
245
245
  Napi::Object Napi::Function::New(size_t argc, const napi_value* args) const;
246
246
  ```
247
247
 
248
- - `[in] argc`: The number of the arguments passed to the contructor function.
248
+ - `[in] argc`: The number of the arguments passed to the constructor function.
249
249
  - `[in] args`: Array of JavaScript values as `napi_value` representing the
250
250
  arguments of the constructor function.
251
251
 
@@ -73,7 +73,7 @@ Napi::Object Napi::FunctionReference::New(const std::initializer_list<napi_value
73
73
  ```
74
74
 
75
75
  - `[in] args`: Initializer list of JavaScript values as `napi_value` representing
76
- the arguments of the contructor function.
76
+ the arguments of the constructor function.
77
77
 
78
78
  Returns a new JavaScript object.
79
79
 
@@ -54,7 +54,7 @@ Napi::HandleScope::~HandleScope();
54
54
 
55
55
  Deletes the `Napi::HandleScope` instance and allows any objects/handles created
56
56
  in the scope to be collected by the garbage collector. There is no
57
- guarantee as to when the gargbage collector will do this.
57
+ guarantee as to when the garbage collector will do this.
58
58
 
59
59
  ### Env
60
60
 
package/doc/hierarchy.md CHANGED
@@ -88,4 +88,4 @@
88
88
  [`Napi::Uint8Array`]: ./typed_array_of.md
89
89
  [`Napi::Value`]: ./value.md
90
90
  [`Napi::VersionManagement`]: ./version_management.md
91
- [`std::exception`]: http://cplusplus.com/reference/exception/exception/
91
+ [`std::exception`]: https://cplusplus.com/reference/exception/exception/
package/doc/number.md CHANGED
@@ -16,7 +16,7 @@ Napi::Number();
16
16
 
17
17
  Returns a new _empty_ `Napi::Number` object.
18
18
 
19
- ### Contructor
19
+ ### Constructor
20
20
 
21
21
  Creates a new instance of a `Napi::Number` object.
22
22
 
@@ -60,7 +60,7 @@ a native method must be deleted before returning from that method. Since
60
60
  deletion, however, care must be taken to create the scope in the right
61
61
  place such that you achieve the desired lifetime.
62
62
 
63
- Taking the earlier example, creating a `Napi::HandleScope` in the innner loop
63
+ Taking the earlier example, creating a `Napi::HandleScope` in the inner loop
64
64
  would ensure that at most a single new value is held alive throughout the
65
65
  execution of the loop:
66
66
 
@@ -8,7 +8,7 @@ For more general information on references, please consult [`Napi::Reference`](r
8
8
  ```cpp
9
9
  #include <napi.h>
10
10
 
11
- using namescape Napi;
11
+ using namespace Napi;
12
12
 
13
13
  void Init(Env env) {
14
14
 
@@ -43,7 +43,7 @@ Napi::Object Example::Init(Napi::Env env, Napi::Object exports) {
43
43
 
44
44
  Napi::FunctionReference* constructor = new Napi::FunctionReference();
45
45
 
46
- // Create a peristent reference to the class constructor. This will allow
46
+ // Create a persistent reference to the class constructor. This will allow
47
47
  // a function called on a class prototype and a function
48
48
  // called on instance of a class to be distinguished from each other.
49
49
  *constructor = Napi::Persistent(func);
@@ -5,8 +5,8 @@ In order to install a native add-on it's important to have all the necessary
5
5
  dependencies installed and well configured (see the [setup](setup.md) section).
6
6
  The end-user will need to compile the add-on when they will do an `npm install`
7
7
  and in some cases this could create problems. To avoid the compilation process it's
8
- possible to ditribute the native add-on in pre-built form for different platform
9
- and architectures. The prebuild tools help to create and distrubute the pre-built
8
+ possible to distribute the native add-on in pre-built form for different platform
9
+ and architectures. The prebuild tools help to create and distribute the pre-built
10
10
  form of a native add-on.
11
11
 
12
12
  The following list report known tools that are compatible with **N-API**:
@@ -1,6 +1,6 @@
1
1
  # Property Descriptor
2
2
 
3
- A [`Napi::Object`](object.md) can be assigned properites via its [`DefineProperty`](object.md#defineproperty) and [`DefineProperties`](object.md#defineproperties) functions, which take PropertyDescrptor(s) as their parameters. The `Napi::PropertyDescriptor` can contain either values or functions, which are then assigned to the `Napi::Object`. Note that a single instance of a `Napi::PropertyDescriptor` class can only contain either one value, or at most two functions. PropertyDescriptors can only be created through the class methods [`Accessor`](#accessor), [`Function`](#function), or [`Value`](#value), each of which return a new static instance of a `Napi::PropertyDescriptor`.
3
+ A [`Napi::Object`](object.md) can be assigned properties via its [`DefineProperty`](object.md#defineproperty) and [`DefineProperties`](object.md#defineproperties) functions, which take PropertyDescriptor(s) as their parameters. The `Napi::PropertyDescriptor` can contain either values or functions, which are then assigned to the `Napi::Object`. Note that a single instance of a `Napi::PropertyDescriptor` class can only contain either one value, or at most two functions. PropertyDescriptors can only be created through the class methods [`Accessor`](#accessor), [`Function`](#function), or [`Value`](#value), each of which return a new static instance of a `Napi::PropertyDescriptor`.
4
4
 
5
5
  ## Example
6
6
 
@@ -150,7 +150,7 @@ static Napi::PropertyDescriptor Napi::PropertyDescriptor::Accessor (
150
150
  void *data = nullptr);
151
151
  ```
152
152
 
153
- * `[in] env`: The environemnt in which to create this accessor.
153
+ * `[in] env`: The environment in which to create this accessor.
154
154
  * `[in] object`: The object on which the accessor will be defined.
155
155
  * `[in] name`: The name used for the getter function.
156
156
  * `[in] getter`: A getter function.
@@ -199,7 +199,7 @@ static Napi::PropertyDescriptor Napi::PropertyDescriptor::Accessor (
199
199
  void *data = nullptr);
200
200
  ```
201
201
 
202
- * `[in] env`: The environemnt in which to create this accessor.
202
+ * `[in] env`: The environment in which to create this accessor.
203
203
  * `[in] object`: The object on which the accessor will be defined.
204
204
  * `[in] name`: The name of the getter and setter function.
205
205
  * `[in] getter`: The getter function.
@@ -0,0 +1,121 @@
1
+ # Thread-safe Functions
2
+
3
+ JavaScript functions can normally only be called from a native addon's main
4
+ thread. If an addon creates additional threads, then node-addon-api functions
5
+ that require a `Napi::Env`, `Napi::Value`, or `Napi::Reference` must not be
6
+ called from those threads.
7
+
8
+ When an addon has additional threads and JavaScript functions need to be invoked
9
+ based on the processing completed by those threads, those threads must
10
+ communicate with the addon's main thread so that the main thread can invoke the
11
+ JavaScript function on their behalf. The thread-safe function APIs provide an
12
+ easy 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
15
+ APIs to create, destroy, and call objects of this type. The differences between
16
+ the two are subtle and are [highlighted below](#implementation-differences).
17
+ Regardless of which type you choose, the APIs between the two are similar.
18
+
19
+ `Napi::[Typed]ThreadSafeFunction::New()` creates a persistent reference that
20
+ holds a JavaScript function which can be called from multiple threads. The calls
21
+ happen asynchronously. This means that values with which the JavaScript callback
22
+ is to be called will be placed in a queue, and, for each value in the queue, a
23
+ call will eventually be made to the JavaScript function.
24
+
25
+ `Napi::[Typed]ThreadSafeFunction` objects are destroyed when every thread which
26
+ uses the object has called `Release()` or has received a return status of
27
+ `napi_closing` in response to a call to `BlockingCall()` or `NonBlockingCall()`.
28
+ The queue is emptied before the `Napi::[Typed]ThreadSafeFunction` is destroyed.
29
+ It is important that `Release()` be the last API call made in conjunction with a
30
+ given `Napi::[Typed]ThreadSafeFunction`, because after the call completes, there
31
+ is no guarantee that the `Napi::[Typed]ThreadSafeFunction` is still allocated.
32
+ For the same reason it is also important that no more use be made of a
33
+ thread-safe function after receiving a return value of `napi_closing` in
34
+ response to a call to `BlockingCall()` or `NonBlockingCall()`. Data associated
35
+ with the `Napi::[Typed]ThreadSafeFunction` can be freed in its `Finalizer`
36
+ callback which was passed to `[Typed]ThreadSafeFunction::New()`.
37
+
38
+ Once the number of threads making use of a `Napi::[Typed]ThreadSafeFunction`
39
+ reaches 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
+
45
+ The choice between `Napi::ThreadSafeFunction` and
46
+ `Napi::TypedThreadSafeFunction` depends largely on how you plan to execute your
47
+ native C++ code (the "callback") on the Node.js thread.
48
+
49
+ ### [`Napi::ThreadSafeFunction`](threadsafe_function.md)
50
+
51
+ This API is designed without N-API 5 native support for [the optional JavaScript
52
+ function callback feature](https://github.com/nodejs/node/commit/53297e66cb).
53
+
54
+ This 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
+
62
+ Note that this functionality comes with some **additional overhead** and
63
+ situational **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" N-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
+
83
+ The `TypedThreadSafeFunction` class is a new implementation to address the
84
+ drawbacks listed above. The API is designed with N-API 5's support of an
85
+ optional function callback. The API will correctly allow developers to pass
86
+ `std::nullptr` instead of a `const Function&` for the callback function
87
+ specified in `::New`. It also provides helper APIs to _target_ N-API 4 and
88
+ construct a no-op `Function` **or** to target N-API 5 and "construct" a
89
+ `std::nullptr` callback. This allows a single codebase to use the same APIs,
90
+ with just a switch of the `NAPI_VERSION` compile-time constant.
91
+
92
+ The 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
+
112
+ In summary, it may be best to use `Napi::TypedThreadSafeFunction` if:
113
+
114
+ - static, compile-time support for targeting N-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
+
121
+ Otherwise, `Napi::ThreadSafeFunction` may be a better choice.