From 22288f55b0dfcea37d641852ed21370ef5d49a3b Mon Sep 17 00:00:00 2001 From: raub Date: Tue, 20 Mar 2018 19:18:35 +0300 Subject: [PATCH] refine emitter --- README.md | 40 ++++++++++++----------------- examples/node-addon/cpp/common.hpp | 10 -------- examples/node-addon/cpp/example.cpp | 29 ++++++--------------- examples/node-addon/cpp/example.hpp | 22 ++++++++-------- examples/node-addon/index.js | 6 ++--- include/event-emitter.hpp | 19 +++++++------- 6 files changed, 46 insertions(+), 80 deletions(-) delete mode 100644 examples/node-addon/cpp/common.hpp diff --git a/README.md b/README.md index 855d01f..763a895 100644 --- a/README.md +++ b/README.md @@ -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 &proto)` and then, -after constructor function instance is created, -`static void extendConstructor(v8::Local &ctorFn)`: + +Now that everything is in place, consider providing **V8** with JS inheritance info: ``` void Example::init(Handle target) { Local proto = Nan::New(newCtor); + // -------------------------- HERE! + // class Example extends EventEmitter + Local 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 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`. diff --git a/examples/node-addon/cpp/common.hpp b/examples/node-addon/cpp/common.hpp deleted file mode 100644 index 7364e3c..0000000 --- a/examples/node-addon/cpp/common.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _COMMON_HPP_ -#define _COMMON_HPP_ - - -#include - -#define DES_CHECK \ - if (_isDestroyed) return; - -#endif /* _COMMON_HPP_ */ diff --git a/examples/node-addon/cpp/example.cpp b/examples/node-addon/cpp/example.cpp index d7583cd..9ac8456 100644 --- a/examples/node-addon/cpp/example.cpp +++ b/examples/node-addon/cpp/example.cpp @@ -1,10 +1,9 @@ #include #include -#include - #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(info.This()); -#define THIS_EVENT_EMITTER \ - EventEmitter *eventEmitter = ObjectWrap::Unwrap(info.This()); - #define THIS_CHECK \ if (example->_isDestroyed) return; -Nan::Persistent Example::_prototype; Nan::Persistent Example::_constructor; @@ -31,22 +26,15 @@ void Example::init(Handle target) { Local 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 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 target) { NAN_METHOD(Example::newCtor) { - std::cout << "Example() 1" << std::endl; - v8::Local 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(); } diff --git a/examples/node-addon/cpp/example.hpp b/examples/node-addon/cpp/example.hpp index c5773f3..f31b504 100644 --- a/examples/node-addon/cpp/example.hpp +++ b/examples/node-addon/cpp/example.hpp @@ -2,33 +2,31 @@ #define _EXAMPLE_HPP_ -#include - -#include "common.hpp" +#include -class Example : public Nan::ObjectWrap { +class Example : public EventEmitter { public: static void init(v8::Handle 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 _prototype; static Nan::Persistent _constructor; bool _isDestroyed; diff --git a/examples/node-addon/index.js b/examples/node-addon/index.js index 53a5abf..908849b 100644 --- a/examples/node-addon/index.js +++ b/examples/node-addon/index.js @@ -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()); }); diff --git a/include/event-emitter.hpp b/include/event-emitter.hpp index efd8471..d371ce3 100644 --- a/include/event-emitter.hpp +++ b/include/event-emitter.hpp @@ -15,9 +15,6 @@ #define EVENT_EMITTER_THIS_CHECK \ if (eventEmitter->_isDestroyed) return; -#define EVENT_EMITTER_DES_CHECK \ - if (_isDestroyed) return; - template 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 jsNames = Nan::New(eventEmitter->_raw.size()); - std::cout << "jsEventNames() 2" << std::endl; + if (eventEmitter->_raw.empty()) { RET_VALUE(jsNames); return;