插件结构
Napi::Addon<T>类继承自Napi::InstanceWrap<T>类。
创建能在从同一源包多次加载到多个 Node.js 线程和 / 或多次加载到同一 Node.js 线程时正常工作的插件,要求它们所持有的所有全局数据都必须与运行它们的环境相关联。将全局数据存储在静态变量中是不安全的,因为这样做没有考虑到插件可能被加载到多个线程中,也没有考虑到插件可能在单个线程中被多次加载。
Napi::Addon<T>类可用于定义整个插件。Napi::Addon<T>子类的实例成为插件的实例,由 Node.js 安全地存储在其各个线程和各个上下文中。因此,存储在Napi::Addon<T>子类实例的实例变量中的任何数据都会被 Node.js 安全存储。使用Napi::Addon<T>::InstanceMethod和 / 或Napi::Addon<T>::DefineAddon向 JavaScript 暴露的函数是Napi::Addon子类的实例方法,因此可以访问存储在实例内部的数据。
Napi::Addon<T>::DefineProperties可用于将Napi::Addon<T>子类实例方法附加到除了将返回给 Node.js 作为插件实例的对象之外的其他对象上。
Napi::Addon<T>类可以与NODE_API_ADDON()和NODE_API_NAMED_ADDON()宏一起使用来定义插件。
示例
cpp
#include <napi.h>
class ExampleAddon : public Napi::Addon<ExampleAddon> {
public:
ExampleAddon(Napi::Env env, Napi::Object exports) {
// 在构造函数中,我们声明插件向JavaScript提供的函数
DefineAddon(exports, {
InstanceMethod("increment", &ExampleAddon::Increment),
// 我们还可以将普通对象附加到`exports`,并将实例方法作为这些子对象的属性
InstanceValue("subObject", DefineProperties(Napi::Object::New(env), {
InstanceMethod("decrement", &ExampleAddon::Decrement)
}), napi_enumerable)
});
}
private:
// 此方法可以访问存储在环境中的数据,因为它是`ExampleAddon`的实例方法,并且在构造函数中被列入传递给`DefineAddon()`的属性描述符中
Napi::Value Increment(const Napi::CallbackInfo& info) {
return Napi::Number::New(info.Env(), ++value);
}
// 此方法可以访问存储在环境中的数据,因为它是`ExampleAddon`的实例方法,并且通过调用`DefineProperties()`将其暴露给JavaScript,附加到对应的对象上
Napi::Value Decrement(const Napi::CallbackInfo& info) {
return Napi::Number::New(info.Env(), --value);
}
// 存储在这些变量中的数据对于插件的每个实例都是唯一的
uint32_t value = 42;
};
// 该宏声明,对于必须加载到Node.js中的每个插件实例,都会创建`ExampleAddon`类的实例
NODE_API_ADDON(ExampleAddon)
上述代码可在 JavaScript 中按如下方式使用:
javascript
'use strict'
const exampleAddon = require('bindings')('example_addon');
console.log(exampleAddon.increment()); // 输出 43
console.log(exampleAddon.increment()); // 输出 44
console.log(exampleAddon.subObject.decrement()); // 输出 43
当 Node.js 加载插件的一个实例时,会创建该类的一个新实例。其构造函数接收环境Napi::Env env和导出对象Napi::Object exports。然后,它可以使用DefineAddon方法要么将方法、访问器和 / 或值附加到exports对象,要么创建自己的exports对象并将方法、访问器和 / 或值附加到该对象上。
注意 :Napi::Addon<T>在内部使用Napi::Env::SetInstanceData()。这意味着插件应仅显式使用Napi::Env::GetInstanceData来检索Napi::Addon<T>类的实例。否则其作用域为全局的变量应存储为Napi::Addon<T>类的实例变量。
使用Napi::Function::New()创建的函数、使用PropertyDescriptor::Accessor()创建的访问器以及值也可以被附加。如果它们的实现需要ExampleAddon实例,可以通过Napi::Env env的GetInstanceData()来获取:
cpp
void ExampleBinding(const Napi::CallbackInfo& info) {
ExampleAddon* addon = info.Env().GetInstanceData<ExampleAddon>();
}
方法
构造函数
创建插件的新实例。
cpp
Napi::Addon(Napi::Env env, Napi::Object exports);
[输入] env:插件正在加载到的环境。[输入] exports:从 JavaScript 接收的导出对象。
通常,构造函数会调用DefineAddon()以将方法、访问器和 / 或值附加到exports。如果构造函数希望替换 Node.js 提供的exports对象,它也可以创建一个新对象并将其作为第一个参数传递给DefineAddon()。
DefineAddon
使用函数、访问器和 / 或值定义插件实例。
cpp
template <typename T>
void Napi::Addon<T>::DefineAddon(Napi::Object exports,
const std::initializer_list<PropertyDescriptor>& properties);
[输入] exports:要返回给 Node.js 作为插件实例的对象。[输入] properties:定义插件的方法、属性访问器和值的插件属性描述符的初始化列表。它们将被设置在exports上。参见:类属性和描述符。
DefineProperties
使用插件实例方法在对象上定义函数、访问器和 / 或值属性。
cpp
template <typename T>
Napi::Object
Napi::Addon<T>::DefineProperties(Napi::Object object,
const std::initializer_list<PropertyDescriptor>& properties);
[输入] object:将接收新属性的对象。[输入] properties:要附加到object的方法、属性访问器和值的属性描述符的初始化列表。参见:类属性和描述符。
返回object。