node-addon-api 1.6.3 → 2.0.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.
- package/.travis.yml +4 -7
- package/CHANGELOG.md +121 -1
- package/CONTRIBUTING.md +66 -0
- package/README.md +12 -3
- package/doc/array_buffer.md +1 -1
- package/doc/async_context.md +10 -0
- package/doc/async_operations.md +1 -1
- package/doc/async_progress_worker.md +344 -0
- package/doc/async_worker.md +97 -25
- package/doc/basic_types.md +19 -0
- package/doc/class_property_descriptor.md +82 -1
- package/doc/cmake-js.md +58 -9
- package/doc/date.md +68 -0
- package/doc/object.md +36 -2
- package/doc/object_wrap.md +14 -3
- package/doc/prebuild_tools.md +2 -2
- package/doc/string.md +3 -0
- package/doc/threadsafe_function.md +320 -0
- package/doc/value.md +9 -0
- package/napi-inl.h +769 -63
- package/napi.h +351 -21
- package/package.json +212 -41
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Class
|
|
1
|
+
# Class property and descriptor
|
|
2
2
|
|
|
3
3
|
Property descriptor for use with `Napi::ObjectWrap::DefineClass()`.
|
|
4
4
|
This is different from the standalone `Napi::PropertyDescriptor` because it is
|
|
@@ -6,6 +6,87 @@ specific to each `Napi::ObjectWrap<T>` subclass.
|
|
|
6
6
|
This prevents using descriptors from a different class when defining a new class
|
|
7
7
|
(preventing the callbacks from having incorrect `this` pointers).
|
|
8
8
|
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```cpp
|
|
12
|
+
#include <napi.h>
|
|
13
|
+
|
|
14
|
+
class Example : public Napi::ObjectWrap<Example> {
|
|
15
|
+
public:
|
|
16
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
17
|
+
Example(const Napi::CallbackInfo &info);
|
|
18
|
+
|
|
19
|
+
private:
|
|
20
|
+
static Napi::FunctionReference constructor;
|
|
21
|
+
double _value;
|
|
22
|
+
Napi::Value GetValue(const Napi::CallbackInfo &info);
|
|
23
|
+
void SetValue(const Napi::CallbackInfo &info, const Napi::Value &value);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
Napi::Object Example::Init(Napi::Env env, Napi::Object exports) {
|
|
27
|
+
Napi::Function func = DefineClass(env, "Example", {
|
|
28
|
+
// Register a class instance accessor with getter and setter functions.
|
|
29
|
+
InstanceAccessor("value", &Example::GetValue, &Example::SetValue),
|
|
30
|
+
// We can also register a readonly accessor by passing nullptr as the setter.
|
|
31
|
+
InstanceAccessor("readOnlyProp", &Example::GetValue, nullptr)
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
constructor = Napi::Persistent(func);
|
|
35
|
+
constructor.SuppressDestruct();
|
|
36
|
+
exports.Set("Example", func);
|
|
37
|
+
|
|
38
|
+
return exports;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Example::Example(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Example>(info) {
|
|
42
|
+
Napi::Env env = info.Env();
|
|
43
|
+
// ...
|
|
44
|
+
Napi::Number value = info[0].As<Napi::Number>();
|
|
45
|
+
this->_value = value.DoubleValue();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Napi::FunctionReference Example::constructor;
|
|
49
|
+
|
|
50
|
+
Napi::Value Example::GetValue(const Napi::CallbackInfo &info) {
|
|
51
|
+
Napi::Env env = info.Env();
|
|
52
|
+
return Napi::Number::New(env, this->_value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void Example::SetValue(const Napi::CallbackInfo &info, const Napi::Value &value) {
|
|
56
|
+
Napi::Env env = info.Env();
|
|
57
|
+
// ...
|
|
58
|
+
Napi::Number arg = value.As<Napi::Number>();
|
|
59
|
+
this->_value = arg.DoubleValue();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Initialize native add-on
|
|
63
|
+
Napi::Object Init (Napi::Env env, Napi::Object exports) {
|
|
64
|
+
Example::Init(env, exports);
|
|
65
|
+
return exports;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Register and initialize native add-on
|
|
69
|
+
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The above code can be used from JavaScript as follows:
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
'use strict';
|
|
76
|
+
|
|
77
|
+
const { Example } = require('bindings')('addon');
|
|
78
|
+
|
|
79
|
+
const example = new Example(11);
|
|
80
|
+
console.log(example.value);
|
|
81
|
+
// It prints 11
|
|
82
|
+
example.value = 19;
|
|
83
|
+
console.log(example.value);
|
|
84
|
+
// It prints 19
|
|
85
|
+
example.readOnlyProp = 500;
|
|
86
|
+
console.log(example.readOnlyProp);
|
|
87
|
+
// Unchanged. It prints 19
|
|
88
|
+
```
|
|
89
|
+
|
|
9
90
|
## Methods
|
|
10
91
|
|
|
11
92
|
### Constructor
|
package/doc/cmake-js.md
CHANGED
|
@@ -1,19 +1,68 @@
|
|
|
1
1
|
# CMake.js
|
|
2
2
|
|
|
3
|
-
**CMake.js** is a build tool that allow native addon
|
|
4
|
-
C++ code into executable form. It works like **[node-gyp](node-gyp.md)** but
|
|
5
|
-
instead of Google's **gyp**
|
|
3
|
+
[**CMake.js**](https://github.com/cmake-js/cmake-js) is a build tool that allow native addon developers to compile their
|
|
4
|
+
C or C++ code into executable form. It works like **[node-gyp](node-gyp.md)** but
|
|
5
|
+
instead of Google's [**gyp**](https://gyp.gsrc.io) tool it is based on the [**CMake**](https://cmake.org) build system.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Quick Start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
### Install CMake
|
|
10
|
+
|
|
11
|
+
CMake.js requires that CMake be installed. Installers for a variety of platforms can be found on the [CMake website](https://cmake.org).
|
|
12
|
+
|
|
13
|
+
### Install CMake.js
|
|
14
|
+
|
|
15
|
+
For developers, CMake.js is typically installed as a global package:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g cmake-js
|
|
19
|
+
cmake-js --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> For *users* of your native addon, CMake.js should be configured as a dependency in your `package.json` as described in the [CMake.js documentation](https://github.com/cmake-js/cmake-js).
|
|
23
|
+
|
|
24
|
+
### CMakeLists.txt
|
|
25
|
+
|
|
26
|
+
Your project will require a `CMakeLists.txt` file. The [CMake.js README file](https://github.com/cmake-js/cmake-js#usage) shows what's necessary.
|
|
27
|
+
|
|
28
|
+
### NAPI_VERSION
|
|
29
|
+
|
|
30
|
+
When building N-API addons, it's crucial to specify the N-API version your code is designed to work with. With CMake.js, this information is specified in the `CMakeLists.txt` file:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
add_definitions(-DNAPI_VERSION=3)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Since N-API is ABI-stable, your N-API addon will work, without recompilation, with the N-API version you specify in `NAPI_VERSION` and all subsequent N-API versions.
|
|
37
|
+
|
|
38
|
+
In the absence of a need for features available only in a specific N-API version, version 3 is a good choice as it is the version of N-API that was active when N-API left experimental status.
|
|
39
|
+
|
|
40
|
+
### NAPI_EXPERIMENTAL
|
|
41
|
+
|
|
42
|
+
The following line in the `CMakeLists.txt` file will enable N-API experimental features if your code requires them:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
add_definitions(-DNAPI_EXPERIMENTAL)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### node-addon-api
|
|
49
|
+
|
|
50
|
+
If your N-API native add-on uses the optional [**node-addon-api**](https://github.com/nodejs/node-addon-api#node-addon-api-module) C++ wrapper, the `CMakeLists.txt` file requires additional configuration information as described on the [CMake.js README file](https://github.com/cmake-js/cmake-js#n-api-and-node-addon-api).
|
|
51
|
+
|
|
52
|
+
## Example
|
|
53
|
+
|
|
54
|
+
A working example of an N-API native addon built using CMake.js can be found on the [node-addon-examples repository](https://github.com/nodejs/node-addon-examples/tree/master/build_with_cmake#building-n-api-addons-using-cmakejs).
|
|
55
|
+
|
|
56
|
+
## **CMake** Reference
|
|
57
|
+
|
|
58
|
+
- [Installation](https://github.com/cmake-js/cmake-js#installation)
|
|
59
|
+
- [How to use](https://github.com/cmake-js/cmake-js#usage)
|
|
11
60
|
- [Using N-API and node-addon-api](https://github.com/cmake-js/cmake-js#n-api-and-node-addon-api)
|
|
12
|
-
- [Tutorials](https://
|
|
13
|
-
- [Use case in the works - ArrayFire.js](https://
|
|
61
|
+
- [Tutorials](https://github.com/cmake-js/cmake-js#tutorials)
|
|
62
|
+
- [Use case in the works - ArrayFire.js](https://github.com/cmake-js/cmake-js#use-case-in-the-works---arrayfirejs)
|
|
14
63
|
|
|
15
64
|
Sometimes finding the right settings is not easy so to accomplish at most
|
|
16
65
|
complicated task please refer to:
|
|
17
66
|
|
|
18
67
|
- [CMake documentation](https://cmake.org/)
|
|
19
|
-
- [CMake.js wiki](https://github.com/cmake-js/cmake-js/wiki)
|
|
68
|
+
- [CMake.js wiki](https://github.com/cmake-js/cmake-js/wiki)
|
package/doc/date.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Date
|
|
2
|
+
|
|
3
|
+
`Napi::Date` class is a representation of the JavaScript `Date` object. The
|
|
4
|
+
`Napi::Date` class inherits its behavior from `Napi::Value` class
|
|
5
|
+
(for more info see [`Napi::Value`](value.md))
|
|
6
|
+
|
|
7
|
+
## Methods
|
|
8
|
+
|
|
9
|
+
### Constructor
|
|
10
|
+
|
|
11
|
+
Creates a new _empty_ instance of a `Napi::Date` object.
|
|
12
|
+
|
|
13
|
+
```cpp
|
|
14
|
+
Napi::Date::Date();
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Creates a new _non-empty_ instance of a `Napi::Date` object.
|
|
18
|
+
|
|
19
|
+
```cpp
|
|
20
|
+
Napi::Date::Date(napi_env env, napi_value value);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `[in] env`: The environment in which to construct the `Napi::Date` object.
|
|
24
|
+
- `[in] value`: The `napi_value` which is a handle for a JavaScript `Date`.
|
|
25
|
+
|
|
26
|
+
### New
|
|
27
|
+
|
|
28
|
+
Creates a new instance of a `Napi::Date` object.
|
|
29
|
+
|
|
30
|
+
```cpp
|
|
31
|
+
static Napi::Date Napi::Date::New(Napi::Env env, double value);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `[in] env`: The environment in which to construct the `Napi::Date` object.
|
|
35
|
+
- `[in] value`: The time value the JavaScript `Date` will contain represented
|
|
36
|
+
as the number of milliseconds since 1 January 1970 00:00:00 UTC.
|
|
37
|
+
|
|
38
|
+
Returns a new instance of `Napi::Date` object.
|
|
39
|
+
|
|
40
|
+
### ValueOf
|
|
41
|
+
|
|
42
|
+
```cpp
|
|
43
|
+
double Napi::Date::ValueOf() const;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Returns the time value as `double` primitive represented as the number of
|
|
47
|
+
milliseconds since 1 January 1970 00:00:00 UTC.
|
|
48
|
+
|
|
49
|
+
## Operators
|
|
50
|
+
|
|
51
|
+
### operator double
|
|
52
|
+
|
|
53
|
+
Converts a `Napi::Date` value to a `double` primitive.
|
|
54
|
+
|
|
55
|
+
```cpp
|
|
56
|
+
Napi::Date::operator double() const;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Example
|
|
60
|
+
|
|
61
|
+
The following shows an example of casting a `Napi::Date` value to a `double`
|
|
62
|
+
primitive.
|
|
63
|
+
|
|
64
|
+
```cpp
|
|
65
|
+
double operatorVal = Napi::Date::New(Env(), 0); // Napi::Date to double
|
|
66
|
+
// or
|
|
67
|
+
auto instanceVal = info[0].As<Napi::Date>().ValueOf();
|
|
68
|
+
```
|
package/doc/object.md
CHANGED
|
@@ -23,12 +23,12 @@ Void Init(Env env) {
|
|
|
23
23
|
|
|
24
24
|
// Assign values to properties
|
|
25
25
|
obj.Set("hello", "world");
|
|
26
|
-
obj.Set(42, "The Answer to Life, the Universe, and Everything");
|
|
26
|
+
obj.Set(uint32_t(42), "The Answer to Life, the Universe, and Everything");
|
|
27
27
|
obj.Set("Douglas Adams", true);
|
|
28
28
|
|
|
29
29
|
// Get properties
|
|
30
30
|
Value val1 = obj.Get("hello");
|
|
31
|
-
Value val2 = obj.Get(42);
|
|
31
|
+
Value val2 = obj.Get(uint32_t(42));
|
|
32
32
|
Value val3 = obj.Get("Douglas Adams");
|
|
33
33
|
|
|
34
34
|
// Test if objects have properties.
|
|
@@ -137,6 +137,40 @@ Returns a `bool` that is true if the `Napi::Object` is an instance created by th
|
|
|
137
137
|
|
|
138
138
|
Note: This is equivalent to the JavaScript instanceof operator.
|
|
139
139
|
|
|
140
|
+
### AddFinalizer()
|
|
141
|
+
```cpp
|
|
142
|
+
template <typename Finalizer, typename T>
|
|
143
|
+
inline void AddFinalizer(Finalizer finalizeCallback, T* data);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `[in] finalizeCallback`: The function to call when the object is garbage-collected.
|
|
147
|
+
- `[in] data`: The data to associate with the object.
|
|
148
|
+
|
|
149
|
+
Associates `data` with the object, calling `finalizeCallback` when the object is garbage-collected. `finalizeCallback`
|
|
150
|
+
has the signature
|
|
151
|
+
```cpp
|
|
152
|
+
void finalizeCallback(Napi::Env env, T* data);
|
|
153
|
+
```
|
|
154
|
+
where `data` is the pointer that was passed into the call to `AddFinalizer()`.
|
|
155
|
+
|
|
156
|
+
### AddFinalizer()
|
|
157
|
+
```cpp
|
|
158
|
+
template <typename Finalizer, typename T, typename Hint>
|
|
159
|
+
inline void AddFinalizer(Finalizer finalizeCallback,
|
|
160
|
+
T* data,
|
|
161
|
+
Hint* finalizeHint);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- `[in] data`: The data to associate with the object.
|
|
165
|
+
- `[in] finalizeCallback`: The function to call when the object is garbage-collected.
|
|
166
|
+
|
|
167
|
+
Associates `data` with the object, calling `finalizeCallback` when the object is garbage-collected. An additional hint
|
|
168
|
+
may be given. It will also be passed to `finalizeCallback`, which has the signature
|
|
169
|
+
```cpp
|
|
170
|
+
void finalizeCallback(Napi::Env env, T* data, Hint* hint);
|
|
171
|
+
```
|
|
172
|
+
where `data` and `hint` are the pointers that were passed into the call to `AddFinalizer()`.
|
|
173
|
+
|
|
140
174
|
### DefineProperty()
|
|
141
175
|
|
|
142
176
|
```cpp
|
package/doc/object_wrap.md
CHANGED
|
@@ -78,7 +78,7 @@ Napi::Object Init (Napi::Env env, Napi::Object exports) {
|
|
|
78
78
|
return exports;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
//
|
|
81
|
+
// Register and initialize native add-on
|
|
82
82
|
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
|
|
83
83
|
```
|
|
84
84
|
|
|
@@ -161,7 +161,7 @@ static Napi::Function Napi::ObjectWrap::DefineClass(Napi::Env env,
|
|
|
161
161
|
JavaScript constructor function.
|
|
162
162
|
* `[in] properties`: Initializer list of class property descriptor describing
|
|
163
163
|
static and instance properties and methods of the class.
|
|
164
|
-
See: [`Class
|
|
164
|
+
See: [`Class property and descriptor`](class_property_descriptor.md).
|
|
165
165
|
* `[in] data`: User-provided data passed to the constructor callback as `data`
|
|
166
166
|
property of the `Napi::CallbackInfo`.
|
|
167
167
|
|
|
@@ -184,12 +184,23 @@ static Napi::Function Napi::ObjectWrap::DefineClass(Napi::Env env,
|
|
|
184
184
|
JavaScript constructor function.
|
|
185
185
|
* `[in] properties`: Vector of class property descriptor describing static and
|
|
186
186
|
instance properties and methods of the class.
|
|
187
|
-
See: [`Class
|
|
187
|
+
See: [`Class property and descriptor`](class_property_descriptor.md).
|
|
188
188
|
* `[in] data`: User-provided data passed to the constructor callback as `data`
|
|
189
189
|
property of the `Napi::CallbackInfo`.
|
|
190
190
|
|
|
191
191
|
Returns a `Napi::Function` representing the constructor function for the class.
|
|
192
192
|
|
|
193
|
+
### Finalize
|
|
194
|
+
|
|
195
|
+
Provides an opportunity to run cleanup code that requires access to the `Napi::Env`
|
|
196
|
+
before the wrapped native object instance is freed. Override to implement.
|
|
197
|
+
|
|
198
|
+
```cpp
|
|
199
|
+
virtual void Finalize(Napi::Env env);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- `[in] env`: `Napi::Env`.
|
|
203
|
+
|
|
193
204
|
### StaticMethod
|
|
194
205
|
|
|
195
206
|
Creates property descriptor that represents a static method of a JavaScript class.
|
package/doc/prebuild_tools.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
The distribution of a native add-on is just as important as its implementation.
|
|
4
4
|
In order to install a native add-on it's important to have all the necessary
|
|
5
|
-
dependencies installed and well configured (see the [setup](
|
|
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
8
|
possible to ditribute the native add-on in pre-built form for different platform
|
|
9
9
|
and architectures. The prebuild tools help to create and distrubute the pre-built
|
|
10
10
|
form of a native add-on.
|
|
11
11
|
|
|
12
|
-
The following list report
|
|
12
|
+
The following list report known tools that are compatible with **N-API**:
|
|
13
13
|
|
|
14
14
|
- **[node-pre-gyp](https://www.npmjs.com/package/node-pre-gyp)**
|
|
15
15
|
- **[prebuild](https://www.npmjs.com/package/prebuild)**
|
package/doc/string.md
CHANGED
|
@@ -56,6 +56,8 @@ Napi::String::New(napi_env env, const std::string& value);
|
|
|
56
56
|
Napi::String::New(napi_env env, const std::u16::string& value);
|
|
57
57
|
Napi::String::New(napi_env env, const char* value);
|
|
58
58
|
Napi::String::New(napi_env env, const char16_t* value);
|
|
59
|
+
Napi::String::New(napi_env env, const char* value, size_t length);
|
|
60
|
+
Napi::String::New(napi_env env, const char16_t* value, size_t length);
|
|
59
61
|
```
|
|
60
62
|
|
|
61
63
|
- `[in] env`: The `napi_env` environment in which to construct the `Napi::Value` object.
|
|
@@ -64,6 +66,7 @@ Napi::String::New(napi_env env, const char16_t* value);
|
|
|
64
66
|
- `std::u16string&` - represents a UTF16-LE string.
|
|
65
67
|
- `const char*` - represents a UTF8 string.
|
|
66
68
|
- `const char16_t*` - represents a UTF16-LE string.
|
|
69
|
+
- `[in] length`: The length of the string (not necessarily null-terminated) in code units.
|
|
67
70
|
|
|
68
71
|
Returns a new `Napi::String` that represents the passed in C++ string.
|
|
69
72
|
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# ThreadSafeFunction
|
|
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.
|
|
13
|
+
|
|
14
|
+
These APIs provide the type `Napi::ThreadSafeFunction` as well as APIs to
|
|
15
|
+
create, destroy, and call objects of this type.
|
|
16
|
+
`Napi::ThreadSafeFunction::New()` creates a persistent reference that holds a
|
|
17
|
+
JavaScript function which can be called from multiple threads. The calls happen
|
|
18
|
+
asynchronously. This means that values with which the JavaScript callback is to
|
|
19
|
+
be called will be placed in a queue, and, for each value in the queue, a call
|
|
20
|
+
will eventually be made to the JavaScript function.
|
|
21
|
+
|
|
22
|
+
`Napi::ThreadSafeFunction` objects are destroyed when every thread which uses
|
|
23
|
+
the object has called `Release()` or has received a return status of
|
|
24
|
+
`napi_closing` in response to a call to `BlockingCall()` or `NonBlockingCall()`.
|
|
25
|
+
The queue is emptied before the `Napi::ThreadSafeFunction` is destroyed. It is
|
|
26
|
+
important that `Release()` be the last API call made in conjunction with a given
|
|
27
|
+
`Napi::ThreadSafeFunction`, because after the call completes, there is no
|
|
28
|
+
guarantee that the `Napi::ThreadSafeFunction` is still allocated. For the same
|
|
29
|
+
reason it is also important that no more use be made of a thread-safe function
|
|
30
|
+
after receiving a return value of `napi_closing` in response to a call to
|
|
31
|
+
`BlockingCall()` or `NonBlockingCall()`. Data associated with the
|
|
32
|
+
`Napi::ThreadSafeFunction` can be freed in its `Finalizer` callback which was
|
|
33
|
+
passed to `ThreadSafeFunction::New()`.
|
|
34
|
+
|
|
35
|
+
Once the number of threads making use of a `Napi::ThreadSafeFunction` reaches
|
|
36
|
+
zero, no further threads can start making use of it by calling `Acquire()`. In
|
|
37
|
+
fact, all subsequent API calls associated with it, except `Release()`, will
|
|
38
|
+
return an error value of `napi_closing`.
|
|
39
|
+
|
|
40
|
+
## Methods
|
|
41
|
+
|
|
42
|
+
### Constructor
|
|
43
|
+
|
|
44
|
+
Creates a new empty instance of `Napi::ThreadSafeFunction`.
|
|
45
|
+
|
|
46
|
+
```cpp
|
|
47
|
+
Napi::Function::ThreadSafeFunction();
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Constructor
|
|
51
|
+
|
|
52
|
+
Creates a new instance of the `Napi::ThreadSafeFunction` object.
|
|
53
|
+
|
|
54
|
+
```cpp
|
|
55
|
+
Napi::ThreadSafeFunction::ThreadSafeFunction(napi_threadsafe_function tsfn);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- `tsfn`: The `napi_threadsafe_function` which is a handle for an existing
|
|
59
|
+
thread-safe function.
|
|
60
|
+
|
|
61
|
+
Returns a non-empty `Napi::ThreadSafeFunction` instance. When using this
|
|
62
|
+
constructor, only use the `Blocking(void*)` / `NonBlocking(void*)` overloads;
|
|
63
|
+
the `Callback` and templated `data*` overloads should _not_ be used. See below
|
|
64
|
+
for additional details.
|
|
65
|
+
|
|
66
|
+
### New
|
|
67
|
+
|
|
68
|
+
Creates a new instance of the `Napi::ThreadSafeFunction` object. The `New`
|
|
69
|
+
function has several overloads for the various optional parameters: skip the
|
|
70
|
+
optional parameter for that specific overload.
|
|
71
|
+
|
|
72
|
+
```cpp
|
|
73
|
+
New(napi_env env,
|
|
74
|
+
const Function& callback,
|
|
75
|
+
const Object& resource,
|
|
76
|
+
ResourceString resourceName,
|
|
77
|
+
size_t maxQueueSize,
|
|
78
|
+
size_t initialThreadCount,
|
|
79
|
+
ContextType* context,
|
|
80
|
+
Finalizer finalizeCallback,
|
|
81
|
+
FinalizerDataType* data);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- `env`: The `napi_env` environment in which to construct the
|
|
85
|
+
`Napi::ThreadSafeFunction` object.
|
|
86
|
+
- `callback`: The `Function` to call from another thread.
|
|
87
|
+
- `[optional] resource`: An object associated with the async work that will be
|
|
88
|
+
passed to possible async_hooks init hooks.
|
|
89
|
+
- `resourceName`: A JavaScript string to provide an identifier for the kind of
|
|
90
|
+
resource that is being provided for diagnostic information exposed by the
|
|
91
|
+
async_hooks API.
|
|
92
|
+
- `maxQueueSize`: Maximum size of the queue. `0` for no limit.
|
|
93
|
+
- `initialThreadCount`: The initial number of threads, including the main
|
|
94
|
+
thread, which will be making use of this function.
|
|
95
|
+
- `[optional] context`: Data to attach to the resulting `ThreadSafeFunction`.
|
|
96
|
+
- `[optional] finalizeCallback`: Function to call when the `ThreadSafeFunction`
|
|
97
|
+
is being destroyed. This callback will be invoked on the main thread when the
|
|
98
|
+
thread-safe function is about to be destroyed. It receives the context and the
|
|
99
|
+
finalize data given during construction (if given), and provides an
|
|
100
|
+
opportunity for cleaning up after the threads e.g. by calling
|
|
101
|
+
`uv_thread_join()`. It is important that, aside from the main loop thread,
|
|
102
|
+
there be no threads left using the thread-safe function after the finalize
|
|
103
|
+
callback completes. Must implement `void operator()(Env env, DataType* data,
|
|
104
|
+
Context* hint)`, skipping `data` or `hint` if they are not provided.
|
|
105
|
+
Can be retreived via `GetContext()`.
|
|
106
|
+
- `[optional] data`: Data to be passed to `finalizeCallback`.
|
|
107
|
+
|
|
108
|
+
Returns a non-empty `Napi::ThreadSafeFunction` instance.
|
|
109
|
+
|
|
110
|
+
### Acquire
|
|
111
|
+
|
|
112
|
+
Add a thread to this thread-safe function object, indicating that a new thread
|
|
113
|
+
will start making use of the thread-safe function.
|
|
114
|
+
|
|
115
|
+
```cpp
|
|
116
|
+
napi_status Napi::ThreadSafeFunction::Acquire()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Returns one of:
|
|
120
|
+
- `napi_ok`: The thread has successfully acquired the thread-safe function
|
|
121
|
+
for its use.
|
|
122
|
+
- `napi_closing`: The thread-safe function has been marked as closing via a
|
|
123
|
+
previous call to `Abort()`.
|
|
124
|
+
|
|
125
|
+
### Release
|
|
126
|
+
|
|
127
|
+
Indicate that an existing thread will stop making use of the thread-safe
|
|
128
|
+
function. A thread should call this API when it stops making use of this
|
|
129
|
+
thread-safe function. Using any thread-safe APIs after having called this API
|
|
130
|
+
has undefined results in the current thread, as it may have been destroyed.
|
|
131
|
+
|
|
132
|
+
```cpp
|
|
133
|
+
napi_status Napi::ThreadSafeFunction::Release()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Returns one of:
|
|
137
|
+
- `napi_ok`: The thread-safe function has been successfully released.
|
|
138
|
+
- `napi_invalid_arg`: The thread-safe function's thread-count is zero.
|
|
139
|
+
- `napi_generic_failure`: A generic error occurred when attemping to release
|
|
140
|
+
the thread-safe function.
|
|
141
|
+
|
|
142
|
+
### Abort
|
|
143
|
+
|
|
144
|
+
"Abort" the thread-safe function. This will cause all subsequent APIs associated
|
|
145
|
+
with the thread-safe function except `Release()` to return `napi_closing` even
|
|
146
|
+
before its reference count reaches zero. In particular, `BlockingCall` and
|
|
147
|
+
`NonBlockingCall()` will return `napi_closing`, thus informing the threads that
|
|
148
|
+
it is no longer possible to make asynchronous calls to the thread-safe function.
|
|
149
|
+
This can be used as a criterion for terminating the thread. Upon receiving a
|
|
150
|
+
return value of `napi_closing` from a thread-safe function call a thread must
|
|
151
|
+
make no further use of the thread-safe function because it is no longer
|
|
152
|
+
guaranteed to be allocated.
|
|
153
|
+
|
|
154
|
+
```cpp
|
|
155
|
+
napi_status Napi::ThreadSafeFunction::Abort()
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Returns one of:
|
|
159
|
+
- `napi_ok`: The thread-safe function has been successfully aborted.
|
|
160
|
+
- `napi_invalid_arg`: The thread-safe function's thread-count is zero.
|
|
161
|
+
- `napi_generic_failure`: A generic error occurred when attemping to abort
|
|
162
|
+
the thread-safe function.
|
|
163
|
+
|
|
164
|
+
### BlockingCall / NonBlockingCall
|
|
165
|
+
|
|
166
|
+
Calls the Javascript function in either a blocking or non-blocking fashion.
|
|
167
|
+
- `BlockingCall()`: the API blocks until space becomes available in the queue.
|
|
168
|
+
Will never block if the thread-safe function was created with a maximum queue
|
|
169
|
+
size of `0`.
|
|
170
|
+
- `NonBlockingCall()`: will return `napi_queue_full` if the queue was full,
|
|
171
|
+
preventing data from being successfully added to the queue.
|
|
172
|
+
|
|
173
|
+
There are several overloaded implementations of `BlockingCall()` and
|
|
174
|
+
`NonBlockingCall()` for use with optional parameters: skip the optional
|
|
175
|
+
parameter for that specific overload.
|
|
176
|
+
|
|
177
|
+
**These specific function overloads should only be used on a `ThreadSafeFunction`
|
|
178
|
+
created via `ThreadSafeFunction::New`.**
|
|
179
|
+
|
|
180
|
+
```cpp
|
|
181
|
+
napi_status Napi::ThreadSafeFunction::BlockingCall(DataType* data, Callback callback) const
|
|
182
|
+
|
|
183
|
+
napi_status Napi::ThreadSafeFunction::NonBlockingCall(DataType* data, Callback callback) const
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- `[optional] data`: Data to pass to `callback`.
|
|
187
|
+
- `[optional] callback`: C++ function that is invoked on the main thread. The
|
|
188
|
+
callback receives the `ThreadSafeFunction`'s JavaScript callback function to
|
|
189
|
+
call as an `Napi::Function` in its parameters and the `DataType*` data pointer
|
|
190
|
+
(if provided). Must implement `void operator()(Napi::Env env, Function
|
|
191
|
+
jsCallback, DataType* data)`, skipping `data` if not provided. It is not
|
|
192
|
+
necessary to call into JavaScript via `MakeCallback()` because N-API runs
|
|
193
|
+
`callback` in a context appropriate for callbacks.
|
|
194
|
+
|
|
195
|
+
**These specific function overloads should only be used on a `ThreadSafeFunction`
|
|
196
|
+
created via `ThreadSafeFunction(napi_threadsafe_function)`.**
|
|
197
|
+
|
|
198
|
+
```cpp
|
|
199
|
+
napi_status Napi::ThreadSafeFunction::BlockingCall(void* data) const
|
|
200
|
+
|
|
201
|
+
napi_status Napi::ThreadSafeFunction::NonBlockingCall(void* data) const
|
|
202
|
+
```
|
|
203
|
+
- `data`: Data to pass to `call_js_cb` specified when creating the thread-safe
|
|
204
|
+
function via `napi_create_threadsafe_function`.
|
|
205
|
+
|
|
206
|
+
Returns one of:
|
|
207
|
+
- `napi_ok`: The call was successfully added to the queue.
|
|
208
|
+
- `napi_queue_full`: The queue was full when trying to call in a non-blocking
|
|
209
|
+
method.
|
|
210
|
+
- `napi_closing`: The thread-safe function is aborted and cannot accept more
|
|
211
|
+
calls.
|
|
212
|
+
- `napi_invalid_arg`: The thread-safe function is closed.
|
|
213
|
+
- `napi_generic_failure`: A generic error occurred when attemping to add to the
|
|
214
|
+
queue.
|
|
215
|
+
|
|
216
|
+
## Example
|
|
217
|
+
|
|
218
|
+
```cpp
|
|
219
|
+
#include <chrono>
|
|
220
|
+
#include <thread>
|
|
221
|
+
#include <napi.h>
|
|
222
|
+
|
|
223
|
+
using namespace Napi;
|
|
224
|
+
|
|
225
|
+
std::thread nativeThread;
|
|
226
|
+
ThreadSafeFunction tsfn;
|
|
227
|
+
|
|
228
|
+
Value Start( const CallbackInfo& info )
|
|
229
|
+
{
|
|
230
|
+
Napi::Env env = info.Env();
|
|
231
|
+
|
|
232
|
+
if ( info.Length() < 2 )
|
|
233
|
+
{
|
|
234
|
+
throw TypeError::New( env, "Expected two arguments" );
|
|
235
|
+
}
|
|
236
|
+
else if ( !info[0].IsFunction() )
|
|
237
|
+
{
|
|
238
|
+
throw TypeError::New( env, "Expected first arg to be function" );
|
|
239
|
+
}
|
|
240
|
+
else if ( !info[1].IsNumber() )
|
|
241
|
+
{
|
|
242
|
+
throw TypeError::New( env, "Expected second arg to be number" );
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
int count = info[1].As<Number>().Int32Value();
|
|
246
|
+
|
|
247
|
+
// Create a ThreadSafeFunction
|
|
248
|
+
tsfn = ThreadSafeFunction::New(
|
|
249
|
+
env,
|
|
250
|
+
info[0].As<Function>(), // JavaScript function called asynchronously
|
|
251
|
+
"Resource Name", // Name
|
|
252
|
+
0, // Unlimited queue
|
|
253
|
+
1, // Only one thread will use this initially
|
|
254
|
+
[]( Napi::Env ) { // Finalizer used to clean threads up
|
|
255
|
+
nativeThread.join();
|
|
256
|
+
} );
|
|
257
|
+
|
|
258
|
+
// Create a native thread
|
|
259
|
+
nativeThread = std::thread( [count] {
|
|
260
|
+
auto callback = []( Napi::Env env, Function jsCallback, int* value ) {
|
|
261
|
+
// Transform native data into JS data, passing it to the provided
|
|
262
|
+
// `jsCallback` -- the TSFN's JavaScript function.
|
|
263
|
+
jsCallback.Call( {Number::New( env, *value )} );
|
|
264
|
+
|
|
265
|
+
// We're finished with the data.
|
|
266
|
+
delete value;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
for ( int i = 0; i < count; i++ )
|
|
270
|
+
{
|
|
271
|
+
// Create new data
|
|
272
|
+
int* value = new int( clock() );
|
|
273
|
+
|
|
274
|
+
// Perform a blocking call
|
|
275
|
+
napi_status status = tsfn.BlockingCall( value, callback );
|
|
276
|
+
if ( status != napi_ok )
|
|
277
|
+
{
|
|
278
|
+
// Handle error
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Release the thread-safe function
|
|
286
|
+
tsfn.Release();
|
|
287
|
+
} );
|
|
288
|
+
|
|
289
|
+
return Boolean::New(env, true);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
Napi::Object Init( Napi::Env env, Object exports )
|
|
293
|
+
{
|
|
294
|
+
exports.Set( "start", Function::New( env, Start ) );
|
|
295
|
+
return exports;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
NODE_API_MODULE( clock, Init )
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The above code can be used from JavaScript as follows:
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
const { start } = require('bindings')('clock');
|
|
305
|
+
|
|
306
|
+
start(function () {
|
|
307
|
+
console.log("JavaScript callback called with arguments", Array.from(arguments));
|
|
308
|
+
}, 5);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
When executed, the output will show the value of `clock()` five times at one
|
|
312
|
+
second intervals:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
JavaScript callback called with arguments [ 84745 ]
|
|
316
|
+
JavaScript callback called with arguments [ 103211 ]
|
|
317
|
+
JavaScript callback called with arguments [ 104516 ]
|
|
318
|
+
JavaScript callback called with arguments [ 105104 ]
|
|
319
|
+
JavaScript callback called with arguments [ 105691 ]
|
|
320
|
+
```
|