javascript publish subscribe with callback - javascript

Scenario :- a json with checked & unchecked item count needs to be sent to a common function which in turn does some basic validation or shows error. There are different function each handle by different css/js team which call this function & depending on the common function result (true/false) each team/module that provided the json with check/uncheck status does the relevant action. Thus both common function (say getcount) & every independent team calling this function rely on the result of common function manipulate the dom/css independently & the common function too manipulate dom independently.
Instead of conventional way of calling function (say getCount({"chk" : 2 , "unchk" : 4})) i am looking for pusblish/subcribe method which is more cleaner as in Jquery & easy to convey to all as only topic name & contract/json needs to describe (also less if/else clause). Since common function is subscriber & when every independent function publishes the resultant chk/unchek json the common function can easily do the manipulation using the publish/subscribe approach but the independent method has to do counter action as well which is only possible if subscribe function can send the result. I know javascript is asynchronous also i understand that common method can publish (say "resultOfGetCount") which every independent function/module can listen to & do the action but is there any way in either in plain javascript or jquery where in on which subscriber can send the publisher the result in a way similar to $.ajax where in the callback function is called once server call is complete.
Looking for the best approach for such scenario.

Here's a simple publish subscribe model in jQuery from this blog post
var exampleHandle = function(){
//do stuff when topic is published
...
}
function subscribe(topic,handle){
$("#subscription").bind(topic,handle);
}
function publish(topic,params){
$("#subscription").trigger(topic,params)
}
function unsubscribe(topic,handle){
$("#subscription").unbind(topic,handle);
}
where you can use a simple string as a topic to subscribe or unsubscribe to the topic, and attach the handle as a callback function. The handle can also be used to unsubscribe from the topic later if necessary.
The method is based on jQuery’s trigger and bind functions. These
allow you to listen for a custom event on an element, and manually
trigger an event on an element. This provides the basic backbone for
the simple subscription model.
If an application element wants to
subscribe to a topic, they bind a handler to the “subscription
element”. This can be a designated element on the page, or just the
window element. You can also of course use different elements for
different subscriptions. Then, when something publishes to that topic,
the handler function will execute.
For publishing, a function can pass
a topic and parameters to the publish function. This calls jQuery’s
trigger to set off the event topic, passing along the parameters.
These params are passed to the handle function.
If an element wants to
cancel its subscription, they can pass the topic and handle function
to the unsubscribe method. Note that the handle has to be the same
function object that was used to originally subscribe, not a copy or
similar function. You also can use jQuery’s unbind to cancel all
subscriptions to a topic by only specifying the topic without the
handle function.

Related

Javascript prompt vs custom prompt. (chessboardjs promotion)

backstory: In chessboardjs you load the board with callback functions for specific events. Chess mechanic that gives me problem is the promotion. I need to hold my callback, prompt a user for a piece he wants to promote to, check if it is a valid move and return('snapback') or execute the move.
Stupid solution: If I prompt with classic
promoPiece = prompt();
everything works, but it looks kinda ugly.
Failed solution: But when I try to create a promise that attaches a callback to my overlay element, to get user click on specific piece I fail(i need to make function async to use promises). I try to get the piece as
async function onDrop(args)
{
..code..
promoPiece = await promoPrompt();
..code..
if(invalid())
{return 'snapback'}
}
and the promotion mechanic works, but the return snapback statement does not work because now the promise is returned instead of a string and it is not accepted with the chessboardjs...(I assumed, I did not dig into source)
Question: 1)How does prompt differ from my solution? 2)How does it work? 3)How can i create a custom promotion handler for a synchronous callback? 4)Can i use promoPrompt.then(myResolve) syntax without making onDrop() async?
It is synchronous
Natively (i.e. the code is part of the browser and exposed as an API via the prompt function)
You can't (unless it is just a wrapper around prompt but then you get the native look and feel that you dislike)
Well, yes, but the value will won't be available until that future so you can't return it to the calling function
If you want a custom UI here, then the calling function needs to be able to handle it asynchronously.

Mongoose Post Hook for create() rather than update()

Maybe I'm misunderstanding, but everything I can find for having a post hook for create() on a mongoose model brings up the update() method instead. Are create() and update() the same?
What I want to do is when a User document is created, send a welcome email, without having to manually call the method on every route/controller that creates a user.
I understand a little about pre- and post- hooks, and I have a pre-remove hook:
userSchema.pre('remove', async function() {
for (let response of this.responses) {
Response.findByIdAndRemove(response);
};
});
But I can't find anything within mongoose docs for a post-hook for create().
If create() and update() are the same, what stops this welcome email from being sent any time the user's information is changed? I only want this to send once, at the very beginning.
Let me know if I'm clear as mud
I found the answer, finally, in the Mongoose docs in a roundabout way through a github feature request: schema.queue: http://mongoosejs.com/docs/api.html#schema_Schema-queue
So I define the method(s) that I want to execute at the time the document is instantiated, then just use the schema.queue command like so:
schema.queue('methodName',[args]);
For the time being, I left the args array empty because they're only operating on themselves, so no other information needs to go in.
The docs don't say it specifically, but I would assume since declaring methods looks to be the same as declaring any function, the queue method can be called before or after declaring the method it calls, but I played it safe and put it after.
Man, this is exciting.

How should I deal with an ajax get function, that is reused across multiple pages?

I have a web application with booking/reservation-functionality. One of my core functions is to check whether a booking conflicts with other bookings, and this function is used across multiple pages. Its return data is not usually loaded with a page, as it's request parameters are dependent upon user input. In other words:
I have an ajax function, that gets booking data
It is abstracted away into it's own .js file, for reusability
The ajax function is wrapped in a javascript function.
However, an ajax function is not suitable for my intended use. The wrapper function will return nothing, before the ajax call is complete, due to it's asynchronous nature. If i need to execute something with the returned data, it should be inside the success-function of the ajax call, but as I need different things to happen, based on in which page, and which situation the data is needed.
I see three solutions to my problem. I just can't decide which is the best approach, or if there might be a fourth and better option:
1. Skip the abstraction of the ajax function. In other words, just copy/paste it into every function where I need the data, and voilla; I would have the success-condition function available at all times.
2. Pass a succes-function as a parameter. If i need something dynamic to happen, I could make it so, by passing a function to the ajax-wrapper function, and making sure that the passed function accepts the ajax returned data as it's own parameter.
3. Make the ajax call synchronous. Possible, but kind of ruins the concept of ajax (actually I am also using JSON, so that will make ajax into sjoj).
Honestly, I really can't see that either of the solutions stand out as the winner here. I would greatly appreciate any help.
I suggest using an event based approach.
Inside ajax success you can fire (trigger) an event for example booking-check-complete and the specific page handles the event the way it needs.
This way you keep the benefits of the ajax being well - asynchronous and keep the pages decoupled.
For uses like this I use jQuery event mechanism, but there are also other libraries available. Check it out here - trigger
For example in page one you have:
$( document ).on( "booking-check-complete", function( event, param1, param2 ) {
alert( "Hello from page 1" );
});
On the second page you have:
$( document ).on( "booking-check-complete", function( event, param1, param2 ) {
alert( "Hello from page 2" );
});
And in ajax success:
$( document ).trigger( "booking-check-complete", [ "Custom", "Event" ] );
NOTE
You don't need jQuery to use events as described here
This uses plain javascript, but it is not compatible with IE.
var event = new Event('build');
// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);
// Dispatch the event.
elem.dispatchEvent(event);
No. That violates DRY.
Yes. This is idiomatic JavaScript.
No. That locks up the UI (and synchronous XHR is deprecated).
Option 2 is the standout winner.

Why does the Firebase event 'child_added' fire after the 'value' event?

According to the Firebase documentation:
Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken.
Here is a simple example (jsbin) where child_added fires before value. This behavior was confirmed using the currently latest Firebase version (2.3.1):
var ref = new Firebase("https://reform.firebaseio.com");
ref.child('pets').once('value', function(snapshot) {
snapshot.forEach(function(pet) {
console.log("Pet: " + pet.key());
pet.ref().child('food').once('value', function (foods) {
console.log('value event called for ' + pet.key());
});
pet.ref().child('food').once('child_added', function (foods) {
console.log('child_added event called for ' + pet.key());
});
});
});
In this example, the console log will be:
Pet: cat
Pet: dog
value event called for cat
child_added event called for cat
value event called for dog
child_added event called for dog
Why does the child_added event fire last in this case? Does this not violate the guarantee per the documentation?
To summarize the excellent feedback in the comments and by Firebase Support:
It makes most sense here to use on() instead of once() to register the event listener. In the example of the original post, and to quote Firebase Support:
The on() callback is registered, and when the once() callback is registered it is ordered in reference to the on() callback. Once the once() callback is fired, it's automatically deregistered. Even though the execution of the events are done in a certain order (due to javascript being single threaded), they are being calculated separately from each other.
Frank's correction to that example shows this in action.
The modified example again breaks the "guarantee" because (Firebase Support):
The data is already locally on the client. So once you have run ref.child('pets').on() and the callback happens, all the data under /pets has been retrieved to the client. Now in the callback processing, you are adding additional callbacks to the existing data. When the callback is being added, the client library is immediately firing the callback without waiting for the second one to be registered since all the data is available.
Since I would like to enforce the guarantee in this case where the data is local, I simply register the child_added listener before the value listener, as demonstrated in the correction to the modified example.

nodejs using callback and event

I am new to nodejs programming. so be patient with me.
I have two nodejs modules. One passes passes a message to another nodejs module. the second processes it and pass result back
to the first module.
method 1
first module
:
secondModule.callFunction(message, function(data){
//deal with the return message from the second module
})
:
second module
:
function callfunction(message, callback){
//asynchornous functions for processing
callback(data);
}
:
method 2
same thing but done using event emitters in the second module
first module
:
secondModule.callFunction(message){
})
secondModule.on('done_event', function(data){
//deal with the reply
});
:
second module (uses event emitter)
:
function callFunction(message){
//asynchornous functions for processing
self.emit('done_event', data);
}
:
Are they both correct. what is the difference in these things (both are asynchornous)
or have i done something stupid.
Thanks in advance
Differences between plain callbacks and EventEmitter events (which is node's implementation of publisher-subscriber pattern)
You can attach multiple listeners to same event. Callbacks are one-to-one notifications, events - one-to-many.
You can't return value from event. Events are one way messages.
Often, callbacks follow (error, data1, data2, data3, ...) signature because single callback responsible for normal and error data flow (and async libraries usually expect this behaviour)
EventEmitter-based api, on the other hand tend to separate error and non-error messages
"error" event is special in event emitter: if there is no listener for it, EventEmitter throws an exception. With callbacks it's your responsibility to check first error parameter.
In your example both approaches are valid.
My understanding of events is that events are used when you want to "break" up your processing in pieces, and/or you don't really know when things are happening. So if your callFunction was a long running task (e.g. doing or waiting a lot for IO), you could break it into pieces and submitting, for instance, data events while it's processing, and then finish with a done event. However, if it's merely a "normal" function call, I would simply use a callback.
I'd say events are for plain notifying when an emitter tells everyone interested about some thing happened. It doesn't care what they will do with this fact, it just tells and forgets. Of course you can return a value from an event (by changing fields of an object provided in parameters) but this looks ugly, non-robust and not logical having in mind that event model presumes multiple listeners.
Callbacks OTOH are for requesting a value. You call for user's help with some data and require result.
For example:
Event - server.on('connection'). Client connected, you tell about it and forget.
Callback - server.isIPAllowedCallback(socket): Boolean. There's a client, you want to check if this IP is allowed.
Main reason for this difference is bubbling event model with multiple listeners. In languages where you just use one listener like someObject.onSomeEvent = someEventHandler there's no difference between handlers and callbacks.

Categories