This is all very... abstract.
Which is all well and good.
It's not necessarily the goal of SO to come up with solutions to abstractions like this, because there are a million ways of doing them.
However, a few key points:
Unless you're linking simulated code to user-generated events in some way, the browser is likely going to prevent your simulations from taking over for the user
(imagine browsers letting any JS on the page simulate any keypress or any mouse-click at any time).
This typically means that you're tightly-bound, using some library which isn't meant for consumer use, using browser-specific (ie: FireFox/Chrome/IE) plug-ins which users must install/run, or bust. Pick one (or more).
Custom-Events, with callbacks, as a rule are what will allow you to keep your programs separate, but have them function together.
Zakas does some great talks on Sandboxing, but those are very enterprise-level, end-game type things. They're fantastic, and library builders and system-engineers should totally consider them, but for making the average page, it'd be better to complete the 100 lines you need to write, rather than build out a full framework, with a library which both wraps every module in an enclosure, and injects itself into that module.
That's where Pub-Sub (and Observer)/Moderator(or Mediator) come into play.
Any of the above might also be called an "emitter" or a "generator", et cetera, depending on the library.
Each one of the above is created in basically the same way, and does the same sort of thing.
The goal is to relay results to an audience who wants to listen.
The speaker chooses when to notify the audience, and what to tell them.
The audience chooses to tune in at any time, to await the next broadcast (which might never come, but at least they were paying attention for it), or they can choose to tune out and stop listening for broadcasts.
The differences between them, then, is how the "speaker" knows about the thing that's happening.
Publisher-Subscriber
In publisher-subscriber
, the speaker IS the object that makes things happen.
Look at Twitter.
You sign up for a Twitter account. Once you have it, you can follow anyone you want.
Any time they tweet, you get notified about it.
Anybody can follow you, so that any time you tweet, they are notified about it.
The person who is doing the action publishes that action to any subscribers who want to hear it. There might be 3000 subscribers and one publisher (a newsletter), or 3000 publishers and one subscriber...
There might be publishers who won't subscribe, or subscribers who won't publish... ...but that's the paradigm.
Observer
In observer
, you're talking about an object which is coupled to the thing doing the work.
It might be tight. It might be loose. But there's a thing doing something, and there's a thing that knows exactly what it's doing. Then people bug the watcher for updates.
Think of the days of Baseball, where people listened to the games on radio.
The observer would be the radio-commentator.
He wasn't the one hitting the ball or stealing bases. He was the one in the booth, who saw everything going on, and knew what it all meant, and turned it into user-friendly information for all of the people listening at home.
These days, players can tweet about plays as they're making them, directly to all of their fans (pub-sub
), and I'm sure that FourSquare will find a way to get their geo down to the per-base accuracy, for hands-off updating of who the king of third-base is (for once, it's not Jeff, in his cramped Z28).
Mediator/Moderator
In this case, we're talking about an object which everybody knows about, but nobody knows about one another.
Imagine a call-in talk-radio show.
Everybody knows the show. Everybody can call into the show, and talk with the host. But other than coincidence, nobody knows anything about the other listeners.
It's a little bit different than pub-sub
, because everybody's a publisher, but you don't have to know somebody's Twitter handle to hear from them. You can say Hey Twitter, any time anybody in the world mentions #browns, let me know. I'm starving.
.
It's a little different from observer
because while the moderator IS watching the person who does the work, anybody can be doing the work at any time.
Which one is the right one?
It all depends on what you need, and what you're actually intending to do with it.
Here's how we might make a Moderator:
var Moderator = function () {
var events = {},
notify = function (evtName, data) {
var evt = events[evtName];
if (!evt) { return; }
evt.forEach(function (func) { func(data); });
},
listen = function (evtName, callback) {
events[evtName] = events[evtName] || [];
events[evtName].push(callback);
},
ignore = function (evtName, callback) {
var evt = events[evtName];
if (!evt) { return; }
evt.forEach(function (func, i, arr) {
if (func === callback) { arr.splice(i, 1); }
});
};
return { ignore : ignore,
listen : listen,
notify : notify };
};
Pretty simple and straightforward, right?
Of course, this isn't particularly filled with bells and whistles, like subscribing to only the next time an event fires, or the next-3 times, or whatever...
We might use it like this:
var Game = function () {
var game_moderator = Moderator(),
scoreboard = Scoreboard(),
messages = MessageBoard(),
player_one = Player(),
player_two = Player();
function initialize () {
player_one.initialize(game_moderator);
player_two.initialize(game_moderator);
game_moderator.listen("player:death", scoreboard.update);
game_moderator.listen("player:death", messages.add_kill);
game_moderator.listen("chat:input", messages.add_msg );
}
function start() {}
/* update... draw... etc... */
return {
load : load,
initialize : initialize,
start : start
};
};
var game = Game(),
loading = game.load();
loading.done(function () {
var initializing = game.initialize();
initializing.done(game.start);
});
Meanwhile, Player
might look like this:
var Player = function (name) {
var system,
health = 30,
damage = [],
attack = function () { /* ... */ },
hurt = function (amt, type, from) {
health -= amt;
damage.push({ amount : amt, type : type, from : from });
},
die = function () {
var killing_blow = damage[damage.length - 1];
killing_blow.player = name;
system.notify("player:death", killing_blow);
},
update = function () {
if (health <= 0) { die(); }
},
draw = function () {},
initialize = function (sys) { system = sys; };
return {
initialize : initialize,
update : update,
draw : draw,
hurt : hurt
/* ... */
};
};
So looking back into the Game.initialize
function, we can see that we've got a scoreboard and a message panel which are both going to do things with "player:death" events.
Because of the way the players are called and defined, I'm injecting a reference to the moderator, during their initialization (so that I can keep everything separate: dependency-injection).
But player_one
knows nothing about player_two
, scoreboard
knows nothing about anything, except that something occasionally calls its .update
method and passes in kill information, and messages
gets all kinds of love, but it's the kind where everybody's a stranger...
Going back to your original problem:
If your hidden-input
is being filled in by spying on key-presses, why not build an Observer?
Build an observer which connects to a keyup
event-listener and a keydown
event-listener.
Have that observer turn those events into useful information (for instance: when you hold a key down, the keydown
event fires dozens of times per second -- you probably don't want that... so alert when a new key is added, or alert when a pressed key is released).
Have the hidden-input
subscribe to that.
When the hidden-input
is full, or however your requirements are operating... ...and you want to fire an event off, have a global-moderator (or a moderator which is at the top level of the system that hidden-input
is a part of).
From there, fire an event called "hidden-input-filled"
or whatever is meaningful.
The people who care about that happening can subscribe to that event through the moderator.
That is, of course, if your program is built in such a way that nobody should know about the hidden-input, BUT there are people who should know about hidden-input
's events.
If there are only a select group of things which should know about hidden-input
, and those are the only things which should know about its events, and hidden-input
should also be able to know something about them, then make them pub-sub
.
Or mix and match your connections:
The idea is to build communication which makes sense and tells people what they need to know, and no more.
So if Twitter-users should be sub-pub, but different widgets on the page (timeline vs search vs recent-pictures, etc) shouldn't know much about one another (and certainly not make every picture able to share with every timeline update), then make a global moderator that the whole widget can communicate to other widgets through (like when timelines need to update based on search results), and inside of each widget, have a moderator and/or pub-sub for different connections, between components.
Hope that helps, and I hope that explains why it's easier to engineer a loosely-coupled, large program by doing this, rather than by hijacking real events, and then firing fake ones down the line, intended to target different areas of your program.
In all honesty, if your full site, with all of its programs comes down to: "I've got this input that does this thing, and another input that does another thing", the answer is that it really doesn't matter too much.
When you get to: "I've got a page with 8 spaces for different widgets, and there are 16 possible widgets which could be loaded in any of those 8 slots at any time, and there are some major actions in some widgets which should cause responses in other widgets, and there are lots of events that each widget needs to control internally, and we need to pipe in an AJAX library and a DOM/MVC(or MVVM) libarary to control all of the stuff that goes on inside of each widget, itself, and there's only one of me..."
That's when it's a great idea to hammer out this stuff and hammer out Promises/Deferreds/Futures, and break your big ideas out into smaller pieces, spread out over different points in the life of the running application.