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
`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**:
@ -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`:
```
@ -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,
after constructor function instance is created,
`static void extendConstructor(v8::Local<v8::Function> &ctorFn)`:
Now that everything is in place, consider providing **V8** with JS inheritance info:
```
void Example::init(Handle<Object> target) {
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->SetClassName(JS_STR("Example"));
// -------- dynamic
// Add EventEmitter methods
extendPrototype(proto);
Nan::SetPrototypeMethod(proto, "destroy", destroy);
// -------- static
Local<Function> ctor = Nan::GetFunction(proto).ToLocalChecked();
extendConstructor(ctor);
_prototype.Reset(proto);
_constructor.Reset(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 <iostream>
#include <event-emitter.hpp>
#include "example.hpp"
using namespace v8;
using namespace node;
using namespace std;
@ -12,14 +11,10 @@ using namespace std;
#define THIS_EXAMPLE \
Example *example = ObjectWrap::Unwrap<Example>(info.This());
#define THIS_EVENT_EMITTER \
EventEmitter *eventEmitter = ObjectWrap::Unwrap<EventEmitter>(info.This());
#define THIS_CHECK \
if (example->_isDestroyed) return;
Nan::Persistent<v8::FunctionTemplate> Example::_prototype;
Nan::Persistent<v8::Function> Example::_constructor;
@ -31,22 +26,15 @@ void Example::init(Handle<Object> target) {
Local<FunctionTemplate> parent = Nan::New(EventEmitter::_prototype);
proto->Inherit(parent);
proto->InstanceTemplate()->SetInternalFieldCount(1);
proto->SetClassName(JS_STR("Example"));
// -------- dynamic
Nan::SetPrototypeMethod(proto, "destroy", destroy);
// -------- static
Local<Function> ctor = Nan::GetFunction(proto).ToLocalChecked();
_prototype.Reset(proto);
_constructor.Reset(ctor);
Nan::Set(target, JS_STR("Example"), ctor);
@ -56,19 +44,17 @@ void Example::init(Handle<Object> target) {
NAN_METHOD(Example::newCtor) {
std::cout << "Example() 1" << std::endl;
v8::Local<v8::Function> superCtor = Nan::New(EventEmitter::_constructor);
superCtor->Call(info.This(), 0, nullptr);
std::cout << "Example() 2" << std::endl;
CTOR_CHECK("EventEmitter");
Example *example = new Example();
example->Wrap(info.This());
std::cout << "Example() 3 @" << example << std::endl;
RET_VALUE(info.This());
}
Example::Example() {
Example::Example() : EventEmitter() {
_isDestroyed = false;
@ -86,12 +72,13 @@ void Example::_destroy() { DES_CHECK;
_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();
}

View File

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

View File

@ -7,7 +7,7 @@ console.log('Example', 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);
@ -27,11 +27,11 @@ console.log('setMaxListeners', example.setMaxListeners);
console.log('rawListeners', example.rawListeners);
console.log('destroy', example.destroy);
console.log('index.js', 'ON1');
example.on('evt1', (arg1, arg2) => {
console.log('EVT1', arg1, arg2, example.eventNames());
});
console.log('index.js', 'ON2');
example.once('evt2', (arg1, arg2) => {
console.log('EVT2', arg1, arg2, example.eventNames());
});

View File

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