refine emitter

This commit is contained in:
raub 2018-03-20 19:18:35 +03:00
parent e773b03e93
commit 22288f55b0
6 changed files with 46 additions and 80 deletions

View File

@ -587,6 +587,10 @@ emits an event with the given `name` and, optionally, some additional arguments
subscribes `that[method]` to receive `name` events from this emitter, basically subscribes `that[method]` to receive `name` events from this emitter, basically
`emitter.on(name, that[method])`. `emitter.on(name, that[method])`.
* `virtual void _destroy()` - destroys the object, i.e. deactivates it and frees
resources, also emitting a `'destroy'` event. This is what also called inside
`~EventEmitter()`, but only the first call is effective anyway.
Be sure to add the include directory in **binding.gyp**: Be sure to add the include directory in **binding.gyp**:
@ -596,7 +600,8 @@ Be sure to add the include directory in **binding.gyp**:
], ],
``` ```
Include the **event-emitter.hpp**, it also includes **addon-tools.hpp**. Though it is the same directory for all the **addon-tools**.
Then include the **event-emitter.hpp**, it also includes **addon-tools.hpp**.
Inherit from `EventEmitter`, it already inherits from `Nan::ObjectWrap`: Inherit from `EventEmitter`, it already inherits from `Nan::ObjectWrap`:
``` ```
@ -607,43 +612,30 @@ class Example : public EventEmitter {
} }
``` ```
NOTE: Do not forget to call `EventEmitter::init()` once, in the module `init()`.
First add EventEmitter dynamic methods to the prototype via
`static void extendPrototype(v8::Local<v8::FunctionTemplate> &proto)` and then, Now that everything is in place, consider providing **V8** with JS inheritance info:
after constructor function instance is created,
`static void extendConstructor(v8::Local<v8::Function> &ctorFn)`:
``` ```
void Example::init(Handle<Object> target) { void Example::init(Handle<Object> target) {
Local<FunctionTemplate> proto = Nan::New<FunctionTemplate>(newCtor); Local<FunctionTemplate> proto = Nan::New<FunctionTemplate>(newCtor);
// -------------------------- HERE!
// class Example extends EventEmitter
Local<FunctionTemplate> parent = Nan::New(EventEmitter::_prototype);
proto->Inherit(parent);
// --------------------------
proto->InstanceTemplate()->SetInternalFieldCount(1); proto->InstanceTemplate()->SetInternalFieldCount(1);
proto->SetClassName(JS_STR("Example")); proto->SetClassName(JS_STR("Example"));
// -------- dynamic
// Add EventEmitter methods
extendPrototype(proto);
Nan::SetPrototypeMethod(proto, "destroy", destroy);
// -------- static
Local<Function> ctor = Nan::GetFunction(proto).ToLocalChecked(); Local<Function> ctor = Nan::GetFunction(proto).ToLocalChecked();
extendConstructor(ctor); _prototype.Reset(proto);
_constructor.Reset(ctor);
Nan::Set(target, JS_STR("Example"), ctor); Nan::Set(target, JS_STR("Example"), ctor);
} }
``` ```
NOTE: after a `v8::Function` is created from the `v8::FunctionTemplate`, no
additional methods can be added to the prototype. Also static members can only
be added to the created `v8::Function` representing the constructor. This is why
there are 2 extend methods: `extendPrototype` and `extendConstructor`.

View File

@ -1,10 +0,0 @@
#ifndef _COMMON_HPP_
#define _COMMON_HPP_
#include <addon-tools.hpp>
#define DES_CHECK \
if (_isDestroyed) return;
#endif /* _COMMON_HPP_ */

View File

@ -1,10 +1,9 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <event-emitter.hpp>
#include "example.hpp" #include "example.hpp"
using namespace v8; using namespace v8;
using namespace node; using namespace node;
using namespace std; using namespace std;
@ -12,14 +11,10 @@ using namespace std;
#define THIS_EXAMPLE \ #define THIS_EXAMPLE \
Example *example = ObjectWrap::Unwrap<Example>(info.This()); Example *example = ObjectWrap::Unwrap<Example>(info.This());
#define THIS_EVENT_EMITTER \
EventEmitter *eventEmitter = ObjectWrap::Unwrap<EventEmitter>(info.This());
#define THIS_CHECK \ #define THIS_CHECK \
if (example->_isDestroyed) return; if (example->_isDestroyed) return;
Nan::Persistent<v8::FunctionTemplate> Example::_prototype;
Nan::Persistent<v8::Function> Example::_constructor; Nan::Persistent<v8::Function> Example::_constructor;
@ -31,22 +26,15 @@ void Example::init(Handle<Object> target) {
Local<FunctionTemplate> parent = Nan::New(EventEmitter::_prototype); Local<FunctionTemplate> parent = Nan::New(EventEmitter::_prototype);
proto->Inherit(parent); proto->Inherit(parent);
proto->InstanceTemplate()->SetInternalFieldCount(1); proto->InstanceTemplate()->SetInternalFieldCount(1);
proto->SetClassName(JS_STR("Example")); proto->SetClassName(JS_STR("Example"));
// -------- dynamic // -------- dynamic
Nan::SetPrototypeMethod(proto, "destroy", destroy); Nan::SetPrototypeMethod(proto, "destroy", destroy);
// -------- static // -------- static
Local<Function> ctor = Nan::GetFunction(proto).ToLocalChecked(); Local<Function> ctor = Nan::GetFunction(proto).ToLocalChecked();
_prototype.Reset(proto);
_constructor.Reset(ctor); _constructor.Reset(ctor);
Nan::Set(target, JS_STR("Example"), ctor); Nan::Set(target, JS_STR("Example"), ctor);
@ -56,19 +44,17 @@ void Example::init(Handle<Object> target) {
NAN_METHOD(Example::newCtor) { NAN_METHOD(Example::newCtor) {
std::cout << "Example() 1" << std::endl; CTOR_CHECK("EventEmitter");
v8::Local<v8::Function> superCtor = Nan::New(EventEmitter::_constructor);
superCtor->Call(info.This(), 0, nullptr);
std::cout << "Example() 2" << std::endl;
Example *example = new Example(); Example *example = new Example();
example->Wrap(info.This()); example->Wrap(info.This());
std::cout << "Example() 3 @" << example << std::endl;
RET_VALUE(info.This()); RET_VALUE(info.This());
} }
Example::Example() { Example::Example() : EventEmitter() {
_isDestroyed = false; _isDestroyed = false;
@ -86,12 +72,13 @@ void Example::_destroy() { DES_CHECK;
_isDestroyed = true; _isDestroyed = true;
EventEmitter::_destroy();
} }
NAN_METHOD(Example::destroy) { THIS_EXAMPLE; THIS_CHECK; THIS_EVENT_EMITTER; NAN_METHOD(Example::destroy) { THIS_EXAMPLE; THIS_CHECK;
eventEmitter->_destroy();
example->_destroy(); example->_destroy();
} }

View File

@ -2,33 +2,31 @@
#define _EXAMPLE_HPP_ #define _EXAMPLE_HPP_
#include <addon-tools.hpp> #include <event-emitter.hpp>
#include "common.hpp"
class Example : public Nan::ObjectWrap { class Example : public EventEmitter {
public: public:
static void init(v8::Handle<v8::Object> target); static void init(v8::Handle<v8::Object> target);
private: protected:
Example(); Example();
virtual ~Example(); ~Example();
static NAN_METHOD(newCtor);
static NAN_METHOD(destroy);
void _destroy(); void _destroy();
private:
static NAN_METHOD(newCtor);
static NAN_METHOD(destroy);
private: private:
static Nan::Persistent<v8::FunctionTemplate> _prototype;
static Nan::Persistent<v8::Function> _constructor; static Nan::Persistent<v8::Function> _constructor;
bool _isDestroyed; bool _isDestroyed;

View File

@ -7,7 +7,7 @@ console.log('Example', Example);
const example = new Example(); const example = new Example();
console.log('example 0', example); console.log('example 0', example, 'instanceof EventEmitter', example instanceof EventEmitter);
console.log('static listenerCount', EventEmitter.listenerCount); console.log('static listenerCount', EventEmitter.listenerCount);
@ -27,11 +27,11 @@ console.log('setMaxListeners', example.setMaxListeners);
console.log('rawListeners', example.rawListeners); console.log('rawListeners', example.rawListeners);
console.log('destroy', example.destroy); console.log('destroy', example.destroy);
console.log('index.js', 'ON1');
example.on('evt1', (arg1, arg2) => { example.on('evt1', (arg1, arg2) => {
console.log('EVT1', arg1, arg2, example.eventNames()); console.log('EVT1', arg1, arg2, example.eventNames());
}); });
console.log('index.js', 'ON2');
example.once('evt2', (arg1, arg2) => { example.once('evt2', (arg1, arg2) => {
console.log('EVT2', arg1, arg2, example.eventNames()); console.log('EVT2', arg1, arg2, example.eventNames());
}); });

View File

@ -15,9 +15,6 @@
#define EVENT_EMITTER_THIS_CHECK \ #define EVENT_EMITTER_THIS_CHECK \
if (eventEmitter->_isDestroyed) return; if (eventEmitter->_isDestroyed) return;
#define EVENT_EMITTER_DES_CHECK \
if (_isDestroyed) return;
template <typename T> template <typename T>
struct StaticHolder { struct StaticHolder {
@ -136,13 +133,13 @@ public:
} }
void _destroy() { EVENT_EMITTER_DES_CHECK; virtual void _destroy() { DES_CHECK;
_isDestroyed = true; _isDestroyed = true;
emit("destroy"); emit("destroy");
} }
private: protected:
EventEmitter () { EventEmitter () {
_isDestroyed = false; _isDestroyed = false;
@ -153,11 +150,15 @@ private:
virtual ~EventEmitter () { _destroy(); } virtual ~EventEmitter () { _destroy(); }
private:
static NAN_METHOD(newCtor) { static NAN_METHOD(newCtor) {
std::cout << "EventEmitter() 1" << std::endl;
CTOR_CHECK("EventEmitter");
EventEmitter *eventEmitter = new EventEmitter(); EventEmitter *eventEmitter = new EventEmitter();
eventEmitter->Wrap(info.This()); eventEmitter->Wrap(info.This());
std::cout << "EventEmitter() 2 : @" << eventEmitter << std::endl;
RET_VALUE(info.This()); RET_VALUE(info.This());
} }
@ -213,10 +214,8 @@ private:
static NAN_METHOD(jsEventNames) { THIS_EVENT_EMITTER; static NAN_METHOD(jsEventNames) { THIS_EVENT_EMITTER;
std::cout << "jsEventNames() 1: @" << eventEmitter << " x " << eventEmitter->_raw.size() << std::endl;
v8::Local<v8::Array> jsNames = Nan::New<v8::Array>(eventEmitter->_raw.size()); v8::Local<v8::Array> jsNames = Nan::New<v8::Array>(eventEmitter->_raw.size());
std::cout << "jsEventNames() 2" << std::endl;
if (eventEmitter->_raw.empty()) { if (eventEmitter->_raw.empty()) {
RET_VALUE(jsNames); RET_VALUE(jsNames);
return; return;