You are on the right track, I will try to give you this extra push that you are talking about:
You need a free connection, pub-sub is a good way to go.
But you really do not need this "intermediary", each module should ideally be autonomous and encapsulate its own logic.
This is done as follows: each module depends on the pubsub service, subscribes to all relevant events and acts on them. Each module also publishes events that may be related to others (code samples in a minute, carry me).
I think the bit that you might miss is that modules that use events are unlikely to become just ordinary models. They will have some logic in them and can also hold the model (which they update when events are received).
So, instead of dataModule , you will have more dataLoaderModule , which will publish the data model (for example, {data: 3} ) as soon as it finishes loading.
Another big requirement that you ask is data sharing, avoiding global instance variables - this is a very important concept, as well as a step in the right direction. What you missed in your solution for this is dependency injection, or at least a modular system that allows you to define dependencies.
You see, an event-driven application does not necessarily mean that every piece of code must communicate using events. The application configuration model or the service is what I would like to introduce (when using DI, for example, in Angular), what is required (when using AMD / CommonJS) or import (when using ES6 modules).
(that is, and then exchange data with a utility that uses events).
It is not clear in your example whether configModule static application configuration or some kind of handle that I can configure from the user interface. If this is a static config application - I would enter it.
Now consider a few examples:
Assuming the following:
- Instead of
dataModule we have dataLoaderModule configModule is a static configuration model.- We use AMD modules (and not the ES6 modules that I prefer), because I see that you stick to using only ES5 functions (I don't see classes or constants).
We would have:
data-loader.js (also known as dataLoaderModule)
define(['pubsub'], function (pubsub) { // ... load data using some logic... // and publish it pubsub.publish('data-loaded', {data: 3}); });
configuration.js (aka configModule)
define([], function () { return {factor: 2}; });
display.js (aka displayModule)
define(['configuration', 'pubsub'], function (configuration, pubsub) { var displayModule = { display: function (data, factor) { console.log(data * factor); } }; pubsub.subscribe('data-loaded', function (data) { displayModule.display(data, configuration.factor); }); });
What is it.
You will notice that there are no global variables (not even pubsub), instead we require (or introduce) our dependencies.
Here you may ask: βwhat if I meant that my configuration has changed from the user interface?β, So let's see also:
In this case, I would rather rename configModule to settingsDisplayModule (following your naming convention).
In addition, in a more realistic application, user interface modules usually contain a model, so do this too.
And it also allows you to call them "views" instead of "displayModules", and we will have:
data-loader.js (also known as dataLoaderModule)
define(['pubsub'], function (pubsub) { // ... load data using some logic... // and publish it pubsub.publish('data-loaded', {data: 3}); });
settings-view.js (aka settingsDisplayModule, aka config)
define(['pubsub'], function (pubsub) { var settingsModel = {factor: 2}; var settingsView = { display: function () { console.log(settingsModel); // and when settings (aka config) changes due to user interaction, // we publish the new settings ... pubsub.publish('setting-changed', settingsModel); } }; });
data-view.js (aka displayModule)
define(['pubsub'], function (pubsub) { var model = { data: null, factor: 0 }; var view = { display: function () { if (model.data && model.factor) { console.log(model.data * model.factor); } else { // whatever you do/show when you don't have data } } }; pubsub.subscribe('data-loaded', function (data) { model.data = data; view.display(); }); pubsub.subscribe('setting-changed', function (settings) { model.factor = settings.factor; view.display(); }); });
What is it.
Hope this helps :)
If not, comment!